 So, hi, my name is Hari Gopal. I'm the engineering lead at a small team that works out here in Bengaluru called Startup Village. And I have been working on a personal project for about a year now, a password manager for Teams. So why a password manager? A password manager is a tool that I have used throughout my career. And there was always something about them that were features that I didn't like, something about them that ticked me off, everything that I use, some feature that I didn't like, something that I just plain hated. So I thought, well, why shouldn't I make one? I have been working on web applications for well over 10 years now. So why shouldn't I build one? So that's exactly what I did. About a year ago, I decided to build one. I really wanted to build an application that would run on the desktop and something that would run offline. So I picked framework and tooling that I was familiar with. I chose React for the front end, React and Electron for the front end, and Ruby and Rails for the back end. And I got started. But after a few months, I started running into a few issues, especially because I had chosen to build a proof of concept and I had made the decision to not write tests. So that sort of came back to bite me. What I should have done probably in hindsight was write test from the scratch. But now that I was where I was, I had a few choices. I could either start writing tests and do TDD going forward, or I could try something out that I had been hearing about from what seemed like every direction, and that was to introduce static typing. Now, I didn't really have any experience with static typing till that point of time. So... But it looked cool. I mean, there were features that I thought made sense, and I thought, well, why shouldn't I try this out? I might as well learn something new while I'm doing this. So I shopped around. I looked at what my options were at that point of time. And there were four that stood out. There was TypeScript and Flow if I wanted to keep my code base intact, and I wanted to gradually introduce static typing to my code base. And then there was ReasonML and Elm if I wanted to completely convert my code base to a static-type language. And I ended up choosing Reason because of a couple of things. First, ReasonML looks a lot like JavaScript. It's syntax is very familiar. I liked that. I liked that I didn't have to learn something completely new. But it also had features that I had never seen before, and that was exciting. Two, ReasonML is created by Jordan Woke, who you probably know is the creator of React, and I love React. So there's a lot of intellectual powerhouse behind Reason. Third and most importantly, I have two friends who have been working with ReasonML, who had been working with ReasonML for over a year at that point of time. And I knew that since I didn't have any prior experience with static-typing languages, I would need help and I was sort of looking forward to bugging them for help. So what is Reason? ReasonML is actually not even a true language. It's a new syntax for OCaml, a 20-year-old systems language, which itself is derived from a 45-year-old meta language, which means that it's part of the ML family of languages. Which is a smart people language. And what's special about OCaml is that there is a project tenant called BuckleScript, written by some fine folks over at Bloomberg. And what BuckleScript does is it takes OCaml and converts it to JavaScript. And what's special about the JavaScript that BuckleScript creates is that it is very clean, very readable, and it is also quite performant. So Reason, toolchain, it takes ReasonML code, passes it through the toolchain, converts it to OCaml, then uses BuckleScript, and then converts it to JavaScript, which seems kind of complicated. And it only seems that way because the toolchain works so well that all of these shenanigans are hidden behind the scene. So we don't really get to know all the different steps that it goes through. We just see Reason code and the output JavaScript. How hard is it to get started? Well, I can safely assume that most of you are JavaScript developers here, which means you probably have node installed on your system, which means there are only two steps. You install VS Platform, and then you install recent CLI for your particular platform. And assuming that you have VS code installed on your system, which is, again, very likely, there is a plugin that gives you excellent editor integration. So that really is it. All right, so let's look at some code. But before, just before that, let me point out that ReasonML is statically typed again. And it also has something called sound typing. What it means is that if some Reason code compiles, then it is guaranteed to, then the compiler is guaranteed to know the type for every single binding that you have written. And this is true even if you have not specified what the type for any particular thing is. And that is because it has a type inference mechanism. It has a very good type inference mechanism called the Hindley-Milner type system. That was introduced back in the original Metal language 45 years ago. So it's gone through quite a few iterations. Works very well. And the best way for me to characterize the type system is to say that it feels like a human is sitting there and trying to figure out the types for the code that you have written. And we'll see this in the examples. So this is how we're gonna look at Reason code today. So on the left in black, I'm showing you Reason code. And on the right in white, I'll show you the corresponding JavaScript code that is generated by BuckleScript. So here, I'm simply saying that car is equal to bloom out of the 800 and that compiles to something extremely similar on the JavaScript side. I think particularly interesting going on here. But you'll note that if it compiles, reason knows that car is a string. I'm not saying that it is a string anyway. I don't need to. When I look at it, I know that it's a string. So what is Reason? That's how the type inference mechanism works. Let's look at something a bit more complicated. I'm adding two strings. I'm saying that car plus plus sold out. Plus plus for, is just the string concatenation operator in Reason. So Reason has different operators for different types. It's just a little quirk that you get used to pretty quickly. But if I try to do something like car plus one, that obviously generates a compiler. Why? Because this has type string and your editor would point out that with some squiggly lines at the bottom of car, saying that car is type string, but somewhere wanted int. And by somewhere it means that you're trying to do a plus one. That is not okay. You have to change that. Now Reason also has something that looks very much like JavaScript's objects. In fact, in this example, it looks exactly like an object, but it doesn't compile. And that is because in Reason, these are called records and records must have an explicit type definition. So because Reason doesn't know what the shape of this particular record is right now, we can give this a type. We can say that type car has three properties, color, make and model. All three are strings. And now it compiles. You'll note that I'm not actually saying that my first car is a car. When we look at it, we can tell that my first car looks like a type car. So that's how Reason works. It compiles. And on the JavaScript side, you'll also notice that instead of being an object, it's actually an array of strings. But BuckleScript leaves helpful comments in line because it wants the code to be readable, just in case you need to go in and make changes, some sort of production issue or something. But this is still quite readable. Now there's something in Reason that blew my mind when I saw it for the first time. And that is variance. Variance gives us a way to model different possibilities in code in a way that I have never seen before. So type color is a variant. And I'm saying that it's either red, blue, white or pink. And those are the variance constructors. So you can read this as color is either red or blue or white or pink. Only one of those things. So I'm gonna use variance to change our previous example. I'm gonna say that there is a make manufacturer who is either Maruti or Hindustan Motors. Model is either 800 or Zen or an ambassador. Color is either red or blue or white or pink. And now instead of the type car being having string values, I'm gonna say that make is of type make. Model is of type model. Color is of type color. And with this, we can change our previous record to say make is Maruti. I'm gonna use the constructor. Model is 800. Color is blue. That reads pretty well, I guess. It should not be confusing. And on the JavaScript side, you'll notice that instead of it being a string, those constructors are being converted to integers. Now this is something that a compiler can do with extremely, I mean, perfect accuracy. Machines can do this sort of translation. So we can't, even if we wanted to. But because SpockerScript wants this code to be readable, it still leaves helpful comments in line in the JavaScript output. The truly mind-blowing part about variants is when you try to do something called pattern matching on them. What I've written here is a function production run, which takes a car and then returns the years during which the car was produced as a string. So I'm gonna use the switch statement to pattern match on the cars model. So you can read this as switch on cars model. If it is an 800, give 1983 to 2013. Now you'll notice that there is no explicit return statement in this function because like a lot of languages that you might have seen, the final expression in a function is what is returned from it. So this particular function in reason looks quite simple. If you're a JavaScript developer, it should be pretty readable. But on the JavaScript side, the output is quite complicated. It's requiring something called camel built-in exceptions. And it says in the function, if the match is not equal to zero, throw a match failure. But otherwise return 1983 to 2013. And why is this happening? Why is there so much? Why is it even throwing a failure? Well, it's because we are ignoring a warning from the compiler. It's telling us, you forgot to handle a possible value here. For example, send an ambassador. The thing is the compiler knows that a car's model is one of three things. It's either an 800 or a model, or a send or an ambassador. And it's reminding us that we have forgotten to handle these values. So let's fill the function in, do what we were supposed to do to begin with. So let's fill in the values for ambassador and send. Now on the JavaScript side, you'll notice that it is much cleaner. It's just got converted to a switch statement. And that's it. And the thing to notice, reason knows that this function cannot fail. It is impossible for this function to ever fail because it knows that the car's model is only one of three properties. So it will always return a type string and it'll always satisfy all of the possible inputs. So this is how the compiler works. So assuming that we use variants to model all of the possibilities in our code, how do you say this? It removes a lot of overhead in terms of what we as developers need to keep in mind to remember when we make changes. You are shifting the responsibility for remembering to a machine. And machines are much better at it than we are. So these types that we have written are already useful. It allows us to not have to remember everything that every possibility that our code handles, we shifted that responsibility to the compiler. That's great, it's useful. But this has an issue. It lets me write something like this. Now I have never seen an ambassador in pink on the road. It's a odd thing. Now you could presumably purchase an ambassador and then paint it pink. I would question your taste, but it is something that you can do. So it is within the realm of possibility, but you certainly couldn't purchase a pink ambassador from Hindustan Motors. It was never one of the factory approved colors. Similarly, you could never purchase a pink 800. It just wasn't available in pink. You can, however, purchase a pink Zen. That is one of the approved colors. Huh. However, this is something that you will never see on the road. A Maruti ambassador. What is that? And yet it compiles. It gives you a valid record. There's something wrong here. Why is that? Well, it's because we've defined car as having three properties, make, model, and color, and they are apparently separate, but they're not really separate, are they? In reality, a make, a manufacturer, would have a certain set of models. Is it working? Great. So in reality, a manufacturer would have a certain set of models, and that model would be available in a certain set of colors. And often it's like some, they give it fancy names. These models have fancy named colors. So what really exists in the real world is a nested relationship. Manufacturers have models, models have colors. And there is a way to model this in ReasonML. So the next slide that we're gonna look at has a large chunk of code. Don't be frightened. We will take it from the top down. So the top three lines I'm gonna write ambicolor is either jet black or oyster blue or fire brick red or a crew beach. These are some of the colors, the actual colors that the ambassador was offered in. Similarly, I'm gonna write zen colors. You'll notice that there's a fusion pink in there and then 800 colors. You'll notice there's a blue blaze in there. Now the interesting stuff happens in the second block of lines. I'll write that there's a Maruti model, a set of Maruti models. It's either an 800 or a zen, but the constructor is taking an argument. I'm saying that if it is an 800 color, 800 model, then it needs an 800 color. If it's a zen, then it needs a zen color. Similarly, Hindustan Motors, we're really concerned with one particular model here. So it's an ambassador. It has an ambassador color, an ambicolor. Now, your make is either a Maruti or a Hindustan Motors, but if it's a Maruti, it must be a Maruti model. If it's a Hindustan Motors, then it's a Hindustan Motors model. And now we only really have one property left in car, which is make. And because there's only one property, I can actually roll that up and say car is either a Maruti with a Maruti model or a Hindustan Motors with a Hindustan Motors model. Now with these types in place, can we write the cars that we wrote earlier? So we can write a blue Maruti. We can say blue Maruti is a Maruti 800 in blue blaze. This is a nested relationship. From the JavaScript side, you'll notice that it compiles with by requiring a block and then saying, and then representing the nested relationship with blocks. So the values for the particular constructors as integers are still the same, but instead of it being an array, it is now nested. So this compiles, it's valid. How about a pink ambassador? This doesn't compile. What's the error? Constructor fusion pink does not belong to type ambicolor. This is something that the compiler knows. It knows that if it's an ambassador, the constructor only accepts an ambicolor. Fusion pink is not the Zen color. So it doesn't compile. How about a Maruti ambassador? Constructor ambassador does not belong to type Maruti model, same as before. Knows that Maruti only accepts a Maruti model. Ambassador is not. So what we have done here, we've pushed business logic into the type. And this is a pattern that you'll find applied again and again when you're using a functional programming language. And we call this make illegal states unrepresentable. So when types are written correctly, it can prevent you, the developer, from even writing an invalid data structure. In a lot of cases, our applications go into a error state. They have bugs because our state, our data structure tends to contain incorrect data. So if compilers make this impossible by writing correct types, then it can potentially prevent a very large class of errors. But so far, we've only discussed data that exists inside of our code. So far, I have been the one defining the data in my code. What about data that comes from the outside? I definitely have no control over it. For example, you could have some data coming in from an API or you could have a UI, for example. Let's imagine that there's a UI that looks like this. For some reason, it hasn't been designed very well. And the user has been allowed to accept to select Maruti Ambassador in Fusion Think. Now the question of why the UI was designed this way is not relevant, let's just ignore it. Assuming that this form gets submitted, we can assume, we can imagine that our application would have to deal with some values that look like this. Three strings, Maruti, Ambassador, and Fusion Think coming from somewhere outside of our code. Now that it has landed here, what can we do with it? We have to remember that functions in your code, they use the type car. For example, you could have a production run function like we saw earlier. It takes car, returns production run as a string. Or perhaps you have an in-stock, it takes a car, returns a Boolean indicating whether or not the car is in stock. The piece only acts that type car and what you have are these strings. Again, have to remember that we wrote this complex type system just to make it impossible to represent something that is invalid. You can think about it in this way. You can think about the compiler like a child who is trying to fit puzzle pieces together. We've told it that there are rules which let it fit together Maruti 800 and Blue Blaze as a valid car. Or a Maruti Zen in Fusion Think or a Hindustan Motors Ambassador in Jet Black. But if you just randomly take three pieces and ask the compiler to fit them together, that is never going to happen. That is actually a mathematical impossibility. You simply cannot do it. What do we do when you get data like this from the outside? Let's not answer this question right now. Let's do a short recap of what we've done so far. So we've written a type with the explicit purpose of making illegal states unrepresentable. And we did this by using two reasonable language features. We used variants to represent the possibilities for our values and we are relying on the compiler to ensure that those requirements are satisfied. Now, because we did this, we can't just naively assume that data that comes from outside of our code is going to fit into our types. We really need, what we really need is some way to pass the incoming data. Make sure that only valid things are processed as our types and that invalid things are handled properly. And I can call this another pattern. I'm gonna say pass all external data and then force boundaries. I'm not gonna go into much detail on how this particular pattern is implemented. Simply gonna say that we can use pattern matching which we briefly saw in one of the examples and that we can write parser functions that use pattern matching to make sure that data coming from outside is passed correctly and that only valid things become the type of car everything else is handled as it should be. But these are just two patterns. There are more patterns. And this is not even a complete list. This is just a few things that I am aware of. All of these patterns are enabled by features that are present in functional programming languages like ReasonML. Now, when someone, when a developer talks about learning a language, a functional programming language, they don't really mean picking up the languages syntax, learning the language syntax, or even picking up how to use the languages features. What they really mean is learning those patterns. So if you can think of a languages features as the tools that you use to build your application, to do your work, then you can think of patterns as techniques that you learn to do your work properly, to do your work better. I believe that learning patterns makes us better developers. It improves our craft and it improves the quality of the applications that we create. I also believe that ReasonML is a kinder language than JavaScript. It is a strict language to be sure. It doesn't really let us make mistakes. But it does provide really great advice for when you do make mistakes because we will make mistakes. We are after all human. In fact, that warning on the top, on the right side, that large paragraph is what finally taught me how to properly use optional parameters in ReasonML functions. Once again, what you want to be focused on, if and when you choose to learn a functional programming language are the patterns that I just mentioned, not the features. And I have personally discovered that ReasonML is a kind and forgiving companion in that journey. So I hope you guys try ReasonML out for the reasons that I mentioned. And if you ever have any trouble, I'd like to point out that the community is extremely welcoming. There are some really great people in it. You can reach out to the community at ReasonML.chat, which is a forum. If you need immediate help for whatever reason, people are also available on discourse at discourse.gg. ReasonML. Or if you want to reach out to me, I'm on Twitter or on email. Oh, and the password manager for teams that I mentioned at the beginning, it's completely open source. You can find that at morocco.com. And that's there. If you want to take a look at a slice, a very large slice of completely working ReasonML code. So it's a Reason React application with a Ruby on Rails backend that uses GraphQL to connect the two. So that's it from me. Bye-bye. Any questions, please? Hi. So when you were building your application, did you stumble upon things like leaf and nodes in Reason? Because a couple of months ago- Do you speak a bit louder? Am I fine? Yeah. So when you were building your application, did you stumble upon things like leaves and nodes in Reason? Because a couple of months ago, when I checked it out, I looked at the documentation into one and it was as simple as Angular 1's documentation. I am fine. I'm sorry. I'm really sorry, but I'm finding it very difficult to understand. Have you- Did you stumble upon things like leaves and nodes in Reason? Leaves and nodes. Yeah. No, I can't say so. Okay. I'll be perfectly honest. Okay. Because I just had a couple of doubts with that. I couldn't understand that. Okay. So I'd like to point out one thing. If it's a functional programming concept that you would like to learn, Ritesh has a talk next. He has been working on functional programming languages for much longer than I have. He would be an excellent person to ask these specific questions about functional programming concepts. Because he has worked on Haskell and now is working with Elm. So he has quite a bit of experience. Okay. Okay. Hi. Yeah. So like for what kind of applications is like Reason suited for? Like if I have an application, I want to decide between using Reason and JS. So like this is obvious factor key. If I want to enforce some kind of data, structure on the data, then I should use Reason. But what other factors should drive my decision in choosing Reason or not? So for JavaScript developers, it's actually a very easy choice because Reason, you are not going to use Reason in production. You're actually going to use JavaScript. Reason compiles to JavaScript, which means that if you have Reason code base, Reason code inside your code base, what the most common use case would be to have the compiler create JavaScript files and keep that alongside the Reason code. So you have no change in your build process, absolutely no change. So that question is a bit invalid. You can use Reason wherever you are using JavaScript right now. It, one of the design decisions, and I believe one of the reason it is created this way is to increase the ease with which you can adopt Reason. Reason is JavaScript for all practical purposes. Of course, because Reason also compiles to OCaml in the middle, you can also choose to compile to native, but that is a different story and that has a different purpose. Hello. Hey, yeah, the last question maybe. You said that you started working the FJS and then you moved to Reason ML. So what problem do you face working the FJS? Then you chosen Reason ML on top of the FJS, I mean. So it was a complexity that was introduced through a mistake that I made. So as I mentioned, I didn't write tests. So once the code base got to a point, it became large, it became complicated. Adding things, making changes was, I wasn't sure if I made a certain change whether a thing would break. The thing about Staticly-type programming languages is that you have the option of having the compiler make these checks for you. So I'm not saying, do not think that I'm saying that you don't need tests, you still do, but types can do a lot of the work that you would generally give to tests. You're shifting the responsibility to the type system. Still use tests, but with Reason ML in place. So I'll illustrate this with an example. So at one point of time, after during the point of time when I switched from React to Reason React on Turku, the personal manager, I worked on a single commit over a period of two days during which I changed the basic structure of the root state. And because I changed the basic structure, I had to go through the entire code base and make massive amounts of changes in code. And during that point of time, because of his making changes, the compiler was always complaining that something was broken. So the process I followed was, look at what is broken, fix that. Look at what is broken, fix that. And at the end, when it compiled after two days, the entire application worked. There were no mistakes. I have never experienced anything like that while using dynamic languages where you make sweeping changes across your code base and when it compiles, it works. This is an experience that truly needs to be, you need to experience it to believe that it can actually work. You can make massive changes and rely on the type system. You can trust the type system that when it says that these types line up, they do. That is why I switched. That is my primary takeaway. Hi, first of all, great talk. I just have a question that, the function that you mentioned, they, yeah, sorry. So the functions that you mentioned in the slides, I see that they don't have a return types or the arguments were not typed. So why is that? I mean, it's a type language. Once again, reason ML has a type inference mechanism. So when you look at that particular type, can you tell what it is? We can infer, right? So there's something called the type inference mechanism where you don't need to specify a type specifically. You don't need to say that something is a string and it looks like a string. It behaves like a string. It is a string. There's a mechanism called the Hindley-Mendler type system. So that's like a mathematical notation. It's a bit complicated and over the top for this particular talk. But what that system allows the compiler to do is to guess with very good accuracy what the type could be. So it infers a type. Usually it infers a type from how you use it. For example, if you were to have a value coming in from outside and you were to going to treat it like a string, then the compiler infers that it is a string. And then for all future use cases, it treats it as a string and there didn't much to be a string. But what I'm saying is probably incorrect, but that's sort of how it works like. Is that, does that answer your question in some way? Hey, great talk. So here, so what I wanted to know was, if you're, are you using reason ML in your production apps right now? Yes, we are using reason ML as we talk to you. Right. So most likely there will be some parts of the code that still you can't really convert totally to reason ML. Right? So there must be some interrupt going on between the two. So what I want to know is like some, like there are things that I still can't formulate in my head how to do it in reason ML. Right? For example, animation request, animation frame, observables or advancing kind of things, generators. That sort of things. Like, have you ever run into troubles like that and what's your relative percentage to reason ML in your code base right now? The relative percentage is very small right now. So we are actually gradually adopting reason ML. We're not trying to like completely change the code base. So the new things we're building, we're building with reason ML. And reason ML does have extremely good interop with JavaScript. So it's formalized. There is lots of documentation on how to connect your existing JavaScript code to reason ML, how to communicate between the two. You want to call reason functions or if you want to call JavaScript functions from reason, that is possible. And the interop is very good. It's a bit awkward. The syntax for it is probably the most awkward thing you will encounter about reason ML. Writing interop can be, the first time I looked at it, it didn't look quite pretty, but the rules are very simple. So once you learn it, it's pretty easy on how to write the interop bits. Hi. So this talk was extremely brilliant and thank you for that. So one thing I wanted to ask was, do you see soundness of the language as a big advantage of reasonable over alternatives like TypeScript? And like if in the application, there are a lot of interop scenarios involved where you are having interop with vanilla JavaScript, does soundness still remain a large advantage in these cases? Like if the application is entirely written and reasonable, then I can understand that the soundness of the type system prevents a lot of errors. But if you have a lot of interop scenarios, like is this still an advantage as such? So, correct me if I'm wrong. TypeScript, I haven't used TypeScript all that extensively, but you can still have nil in TypeScript, right? Yes. So like the security talk we had a little bit earlier, it's always best to have a sane default. Nil is not sane. In my 10 years of experience as a web developer, I have had more trouble rising from the damned nil or null for you JavaScript developers than anything else. No metadata is on nils, some nil being passed there or here. Nil is not a thing when you think about it. When you have a sound type system, everything has a guaranteed type. It is always known. So yes, I do think soundness matters. When you eliminate nil from the equation, it's, you can think about it from a security perspective. It is a weakness. I don't think that is any particular value to having nil because everywhere where you use nil, it's actually a standard for something else. So if you were to use something like nil in reason and in elm, you'd have something called the option type where you say something, where a thing is some value or none. So it's again a variant. It's actually a variant wherever you see and where you think you should be using nil, probably you should be using a variant and then you introduce soundness to your system. So my question is not really get towards reasonable but just around the ecosystems. So let's say I am a package developer. I want to develop a node package. So it doesn't like the community is fragmented towards like typescript, flow, reasonable. So whenever I want to create a new package, I have to write my type definitions for all these three things. And that is a kind of an overhead for us. If I'm a single developer. By writing types, do you mean like writing definitions on the, there are other sites that provide definitions. Is that what you mean? Yeah, so if I'm exporting a library, so I would provide my own type definitions for it. Would you be writing in JavaScript or in one of the type languages? So in typescript, we have .d.ts files which we typically ship with every node package. But then if my consumers are using flow, then I need to write flow types. And I think reasonable must also be having some similar kind of thing to export its library definitions. So isn't it like an overhead to write for all this? Isn't the community fragmented to write to type definitions in all these different languages? A fragmentation in the community is like a huge topic. One that we could have like our long conversations about. But in this respect, again, interop between JavaScript things that's solved for TypeScript and Flow, I think. The interop works quite well. You can have interop between Flow and TypeScript because fundamentally they come down to JS. So it's always JS at the end of the day. So it is possible in the interop is there. The story is there. Similarly, if you're writing reason, again, interop with JS is possible. Flow has interop with JS. TypeScript has interop with JS. So they all have interop with each other through JS. I think that's sort of the answer to your question, but it's not complete. I admit that it's not complete. That's done with time. Thank you guys. Bye.