Everything you need to know about FFI in Gleam

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
if you've written any gleam you probably know that gleam doesn't compile to Binary like a lot of modern languages instead gleam actually has two compilation targets JavaScript and llang each has different uses youd typically use the JavaScript Target if you're doing some front-end work using a framework like luster or you compile to llang to create super scalable fault tolerant backend services but you may be thinking how does gleam manage to work across both llang and JS for example how come we can access built-in functions like Earl Lang's display play or javascripts console.log that's thanks to gle's excellent support for foreign function interfaces or ffis an ffi is just a way for a programming language to call functions written in another one in gle's case the compiler can substitute the correct function based on your compilation Target ffis aren't limited to the standard library though you can actually write your own and in this video we're going to explore how you might do that why you'd want to and some common pitfalls when creating foreign functions ready to get gleamy before we get started it's worth noting that gleams documentation refers to ffis as external functions I.E they're external to gleam however I'll be using the ffi terminology throughout this video to be more in line with what you might see in other programming languages there's actually nothing special you need to do to start using ffi in your gleam project ffis are built into gleam natively so you don't need to install any special packages or do any extra setup step you don't even have to use a compiler flag it all just works and of course because gleams philosophy is is to make things simple calling out to llang or JavaScript is really easy all you have to do is provide a function signature then decorate it with the at external annotation this takes three arguments the first argument is the language you'd like to Target at the time of recording this is either JavaScript or llang the second argument is the path to the JavaScript or llang source file that contains the function you'd like to call and the last argument is the name of that function one thing to beware of is that the compiler can't infer the parameter or return type to the foreign function you're trying to call so make sure to get those right we'll get into how gleam values are represented in each of the target languages shortly if you don't need access to the values internals from gleam for whatever reason you can create a glean type with no Constructor and use that in your foreign function interface for example this function returns a JavaScript date and this function takes one as an argument but we don't actually need to inspect the value using gleam at all I can just pass it around like any other value and it'll work as expected you can get the string representation of the value using string. inspect or print out the value using io. debug and you'll see that it's prefixed by the name of the target this makes sure you don't mix up gleam and non-g gleam values of course an ffi doesn't just have to have a single Target if you're writing a library for others to use it's common to want to support both JavaScript and llang in this case you can use multiple external annotations to provide implementations for both Targets in fact this is what a lot of the standard Library does for example the io. print line function calls this this internal do print line function which is ultimately just an ffi to erl Lang's i.put cars and javascript's console.log if you only provide one annotation and try compiling for the other Target you'll get an error at compile time but what if you want to use a foreign function for one target but a gleam implementation for the other well you can absolutely do that this comes in handy when you have a function that can be implemented in gleam but one of the target runtimes has a more efficient implementation you can use instead both llang and JavaScript have some standard Library functions that are written in optimiz C or C++ respectively so it can be worth tapping into those if they suit your use case all you have to do is provide a body for a function marked with external in this example the reverse list function will use The Gleam implementation when compiling to JavaScript but it'll use the List's reverse function from the llang standard Library when you're targeting llang if you're curious how this works essentially when there's a foreign implementation available The Gleam compiler will substitute any calls to The Gleam function with the foreign function and if there aren't any available it'll create the defined function as it would any other function and call it normally for example in the main function for the above the generate JavaScript code will call the reverse list function while any calls to reverse list will be substituted for list reverse on Earline like I mentioned earlier it's fairly simple but how are types translated across the boundary between gleam and its targets well this varies depending on where you're compiling to let's start with Earline in the case of primitive types you get pretty much what you'd expect The Gleam Primitives mostly map one to one with the llang ones ins map to ins floats to floats balls to balls since llang doesn't have a string type gleam strings are represented as utf8 bit arrays the only other exception is nil which just becomes an llang atom called nil as for container types again things are pretty much just a onetoone mapping lists tupal and bit arrays all have exact representations in earling when it comes to record types like the built-in result type or any custom defined record types things are a little different since llang doesn't have an exact analog for these gleam will use tupal instead the first element of the tupal will be an erlang atom representing the snake case name of the record Constructor and the remaining elements will be the contained values for example an okay with the int 17 would become the tupal okay 17 and this custom Pokémon type would become a tupal of Pikachu 55 and an empty list this makes it super simple to use your gleam record types in llang you can easily pattern match on them deconstruct them and return them from your functions without breaking a sweat and if this video is making you thirsty for more glean make sure you hit the Subscribe button and the bell below I've got a lot of exciting stuff in the pipeline that you do not want to miss in terms of using your own llang modules in gleam there are a few requirements firstly the module must be placed in the root of the source directory though at the time of recording there's an open issue to change this any functions you want to use in gleam must be exported from the module when setting up the ffi the path argument is just the name of the airline module so that's all for the llang Target but what about JavaScript well JS is a little different for a few reasons the biggest ones are JavaScript Dynamic type system and the fact that its values are often mutable there are a couple of challenges that come with this and we'll get into them shortly but right now let's talk types in most cases JavaScript Primitives are going to map roughly to gleam own Bulls are bulls strings are strings and nil maps to undefined numbers are a bit of a special case since JavaScript doesn't have separate int and Float types both glean type just maap to the number type in JS land because of this when you're writing JS and returning numbers from your ffi functions be extra careful you're returning correctly if you're returning an INT it's probably best to use one of the rounding functions from JavaScript standard Library gleams lists just map directly to JavaScript arrays however JavaScript arrays are heterogenous and contain multiple types whereas gleams lists can't so you'll need to be careful to make sure list always contain values of the same type since JavaScript can't make these guarantees for you JavaScript is also lacking a tupal type glean tupal will just compile to JS arrays so again you'll need to be careful that you've got the right types but you'll also need to make sure that you return arrays of the correct length when going from JS to gleam going back to the reverse example from earlier you might have wondered why we didn't use javascript's array. prototype. reverse firstly this is a method so we can't use it directly we could have created a wrapper function but there's another problem here crucially this method reverses in place which would break gleams immutability guarantees since JavaScript doesn't enforce immutability like gleam does it's important not to modify values in your foreign functions users in gleam land would rightfully expect immutability and it could go badly if their memory started changing out from underneath them record types need some special treatment to when targeting JavaScript glim compiles your custom record types to JS classes you can import these from within your JS modules and construct them like you would any other class if you need to return a result type you can import the okay and error Constructors from thought / gleam MJS which is where the gleam globals live you can also check the specific variants using regular instance of checks using your JS modules in an external annotation is easy the path argument just becomes the path to the JS file containing your foreign functions this currently has to live in The Source directory but the path is relative to the file in which the foreign function interface is defined and make sure you export any functions you'd like to use from gleam you might be tempted to use ffi everywhere especially if you're more familiar with llang or JS than you are with gleam but of course this isn't really recommended generally you should only use ffi in a few specific scenarios the first is if you need to access functions built into the target runtime for example in JavaScript you may need access to node or browser apis whereas those using llang might want to bind to OTP functions you can see good examples of these in The Gleam Earline and gleam JavaScript libraries another good example for JavaScript ffi is PL by Crow haer a collection of bindings for various JavaScript runtimes the second situation is when the underlying platform has a more efficient implementation than you can write yourself in gleam like the reverse example we showed earlier your target platform will probably have some functions written in C or C++ and when you need performance it can be really beneficial to use them it's usually a good idea to keep your foreign functions fairly small where you can if possible you should try to use them to complete a single action or create a single value writing long functions in multiple languages is just going to make things really hard to debug and in the JavaScript case in particular you're likely to get caught up in all sorts of problems with mutability basically write gleam for most things and only reach for ffi if you really need to and then only sparingly ffi opens up a whole host of possibilities when you're writing gleam what will you use it for let me know down in the comments below and if you want to see how you can use someone else's ffis to create beautiful front-end apps in glean click the video on the left or if you fancy leaving your fate in YouTube's hands you might want to try the one on the right see you
Info
Channel: Isaac Harris-Holt
Views: 4,217
Rating: undefined out of 5
Keywords: programming, technology, software engineer, gleam, ffi, javascript, erlang, elixir, functional programming, software engineering, programming language
Id: mreYmQc306c
Channel Id: undefined
Length: 9min 57sec (597 seconds)
Published: Sun Jun 30 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.