Introduction to Gleam
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Subtitle |
| |
Title of Series | ||
Number of Parts | 542 | |
Author | ||
License | CC Attribution 2.0 Belgium: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor. | |
Identifiers | 10.5446/61683 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | |
Genre |
00:00
Erlang distributionTwin primeBuildingFormal languageSystem programmingScale (map)Point (geometry)Scripting languageJava appletAgreeablenessLibrary (computing)Network topologyAsynchronous Transfer ModeFunction (mathematics)Data typeCodeTelecommunicationSocket-SchnittstelleGateway (telecommunications)Message passingElectronic mailing listVariable (mathematics)Dependent and independent variablesLibrary (computing)TuplePattern languageIntegerErlang distributionGateway (telecommunications)ExpressionResultantWrapper (data mining)Projective planeWeb 2.0DiagramFormal languageOperator (mathematics)Dot productRobotType theoryMultiplication signHash functionCompilerWritingKey (cryptography)Point (geometry)MultiplicationPoisson-KlammerConnected spaceBuildingElectronic program guideCore dumpObject (grammar)Repository (publishing)Module (mathematics)Constructor (object-oriented programming)TypprüfungMereologyCodeStandard deviationCategory of beingFunctional (mathematics)Real-time operating systemProgramming languageBlock (periodic table)CASE <Informatik>Pattern matchingOrder (biology)Regulärer Ausdruck <Textverarbeitung>Enumerated typeElement (mathematics)Physical systemRun time (program lifecycle phase)Statement (computer science)Process (computing)Source codeHexagonError messageSlide ruleMessage passingNumberSocket-SchnittstelleDiagramComputer animation
09:04
Event horizonLoop (music)Erlang distributionMessage passingClient (computing)Process (computing)Content (media)Gateway (telecommunications)Gateway (telecommunications)Level (video gaming)Key (cryptography)Functional (mathematics)CASE <Informatik>TupleMessage passingEvent horizonMultiplicationSubject indexingState diagramQR codeClient (computing)Field (computer science)Type theoryLoop (music)Different (Kate Ryan album)Computer fileFrame problemLibrary (computing)Power (physics)Slide ruleProjective planeComputer wormCodeContent (media)Standard deviationVideo game consoleStatement (computer science)Network socketInformationWeb 2.0Variable (mathematics)Pattern languageWritingBoilerplate (text)RobotHexagonDiagramMultiplication signMereologyLink (knot theory)Computer virusText editorPhysical systemRight angleTypprüfungIntegrated development environmentParameter (computer programming)PlanningMacro (computer science)Revision control2 (number)Surjective functionState of matterString (computer science)Disk read-and-write headModule (mathematics)Matching (graph theory)Connected space
18:03
Erlang distributionImplementationComputer animationProgram flowchart
Transcript: English(auto-generated)
00:07
So now we have Harry Bercow with an introduction to GLEAM, which is another language running on Erlang VM, so give it up for him. Hi everyone, my name is Harry and I'm, as
00:24
was said, doing an introduction to GLEAM. You might ask, what is GLEAM? GLEAM is a programming language for building type-safe systems that scale. It's powered primarily by the BEAM, but can also be run on JavaScript targets, too. I thought I'd go first into the three key points which make GLEAM what it is. First, it's safety.
00:41
GLEAM has powerful compile-time type checking built into its core. This helps you write fast code that's integrated with Erlang and Elixir while giving you the safety of a statically typed language. Secondly, it's performance, as was just discussed before, building on the success of Discord, WhatsApp, Ericsson, and more with the BEAM. GLEAM adds no overhead, so you get the same great type safety and performance with an enjoyable syntax.
01:05
And finally, it's friendliness. Both the community and the syntax of GLEAM are friendly. The community is more than happy to help with any problem or just friendly chitchat. They even help write some of this talk. And when you get something wrong, the compiler provides insightful help so that you can hunt down the issues and stop them.
01:21
The syntax of GLEAM is similar to that of Rust, but if you're not from one of those backgrounds, don't worry. There are several guides to get started if you're used to syntax from Python, Elm, Erlang, or even Elixir. Here's an example of the start of the GLEAM project. All GLEAM projects have an exported main function in the project name.glean file, which is within your source folder.
01:42
If you need IO, you can import the standard library's IO module, as shown there. And the standard library contains several modules to help you with everything you can think of, from regex to options, iterators, and more. If you need target-specific standard library features, look at the GLEAM Erlang and GLEAM JavaScript packages, which are both available on hex and GitHub.
02:04
Let's explore some GLEAM examples to get a better understanding of the language. And once we've done that, you can go away and look at the docs yourself for more examples. And we'll go on to building some stuff with Shimmer. Variables in GLEAM are created using the let keyword. They are assigned to a name and a value.
02:20
The name can be reused later by other let bindings, but the values contained within are immutable, meaning the values themselves cannot be changed. Here's an example of blocks. Every block in GLEAM is an expression. All expressions in the block are executed, and then the result of the last expression is returned. So as you can see here, the response will be false, even though hello and 42 plus 12 are evaluated.
02:44
This can be used to build more advanced expressions where the order of operations is important. Here's an example of using the blocks to convert from Fahrenheit to Celsius, being sure to remove the 32 before multiplying and dividing. In GLEAM, lists are all homogenous. This means that elements in a list must all be of the same type.
03:04
If you try and construct a list with multiple types, this will result in a compiler error presenting you with a type error, and showing you where you try to use the multiple different types, so you can find it and correct it. Prepending to a list in GLEAM is very fast, and this is the way that GLEAM's documentation
03:21
recommends that you should add new values to a list. In the standard library, there is a list module, which allows you to do more advanced operations and also add to lists that way. The above example uses two constant lists, well, a constant and a constant list, but the same principles apply whether you have one dynamic and the other constant, or vice versa.
03:42
If you need multiple types in one place, you can use tuples using the hash and bracket syntax there. They can have multiple types and can be pattern matched against. We'll look at pattern matching in a few slides. But if you want to access the values on a tuple, there's always the dot syntax, which I'll show you on the next slide, which is similar to that you'd be used
04:01
to in object-oriented for custom types and objects. Here's an example of a tuple which has two elements, and they're selected using the dot syntax and assigned to their own variables. It's not particularly useful here because they're constants, but with runtime variables, it's easy to access. GLEAM supports custom types, and custom types in GLEAM are a collection of
04:22
keys and their values, and you can see them as objects. There's just one caveat, though. Types in GLEAM do not have methods. Similar to tuples, you can use the dot syntax to access properties within them, but instead of dot and position, you use dot and the
04:42
name. In GLEAM, custom types can have multiple constructors similar to in the Rust ecosystem for enums. This does bring another caveat, though, which is that the dot syntax now only works for keys that are shared across all elements. So in this case, the only key you would be able
05:01
to use the dot syntax with is name. Otherwise, you would have to pattern match against them to make sure that type safety stays. Case statements can match anything. In this first example, we use basic integers, but there's more advanced pattern matching over the next couple slides. You can see we match the first three numbers and produce a value, and otherwise,
05:23
we just consume it as a variable and say we can either use or discard that variable. You can pattern match against tuples here and even extract values from within. In this example, we're checking for two specific paths where one is no and the other is yes. The unique thing about the yes path is that we're discarding the integer in the middle,
05:43
but we could again take that out as a variable and do further checks against it. And if you remember the custom type from earlier, this pattern matches against that, so we can extract the values into certain variables here, like talks and mic, and the
06:02
rest can be thrown away with the two dots. You can also use the two dots and assign that to a variable so that then you can reconstruct the type afterwards to pass it back on somewhere else. There's lots more about Gleam syntax that I don't have time to cover today, such as external functions, generics, the use keyword, and more, and stuff's always
06:21
being added to the syntax. All of it's documented in the language tour, so feel free to have a look over there and get a better understanding of what else is available within Gleam. Now let's get on to building some bots to put our Gleam skills into practice. Shimmer is a library which I've dabbled in and out of over the last 13 months. I started
06:43
as a project to learn Gleam and get into the Beam ecosystem, but in the process I've done much more. I'm doing this talk now, I've started contributing to the Gleam compiler and the wider ecosystem, and I use Elixir and Erlang more day-to-day now. At this point in Shimmer's development, we've moved away from using Erlang foreign functions,
07:04
and now the majority of it is in Gleam. Some key features of Shimmer. First, it's compatibility. While Shimmer is built in Gleam, it can be used in Elixir, Erlang, and any other Beam language. It's published on Hex, and the source code is available online.
07:21
I've been working on some examples for Erlang and Elixir, which I'll publish into the GitHub repository once I've got them to a stable point. Secondly, it's actor-based, as we discussed before with its resilience. Shimmer is built on top of actors, and when you're running in single shard mode, you only have one actor, multiple shards. That's not a problem. We use a
07:45
Erlang's OTP using the Gleam OTP package. And finally, it's type safety. As well as being core to Gleam, it's a useful feature for Shimmer. While building your Discord bot in Gleam, we leverage all of Gleam's type functionality to ensure that the code you write for the Beam is type safe. You only get the full type safety when you write all of your code in Gleam,
08:05
but you can always trust that the core of the library will be type safe. As a little fun fact, moving more and more of Shimmer to Gleam, we're currently at 97% Gleam, and the rest is just Erlang foreign functions for small parts of networking, which are yet to have libraries implemented in Gleam.
08:26
For some of you, this might now be the most interesting part of the talk, and for some of you it might not. But I'm just going to quickly touch on how Discord's gateway works so that you have a better understanding of why we use actors and how that's useful to us in Gleam and with the OTP package.
08:44
Discord bots are powered by Discord's real-time gateway, which uses web sockets to send and receive messages. For Shimmer, we use Erlang's gun library from 99's to receive them, and we use a typed wrapper on top of that, which is based upon Lewis, the creator of Gleam's NERF
09:00
library. The diagram here shows what happens when Shimmer opens a connection to the gateway. We use ETF encoding and hand the frames off to actors to pass, manage them, send them to the event loop, and eventually either trigger handlers or discard them.
09:22
Inside of that, Shimmer has a powerful event loop built on top of actors and messages, which manages multiple messages as well as its own state, both internally and externally accepts messages so that you can send updates to Discord, or internally we can manage the updates. The next slide shows a state diagram which roughly shows how it works.
09:41
The state diagram shows what happens at different stages depending on the initial message. For example here, if you have a web socket frame, it's then passed, we then check what it's asking us to do, we then either respond, discard it, stop the bot, and then terminate. This diagram isn't complete at all, but it just shows you how complicated
10:01
it can get very quickly, and how Gleam and the Beam can easily handle it. Now that we know some Gleam and understand how Shimmer works under the hood, let's actually get our bot written. Above the boilerplate we're going to use, and as a side note, the final code for all of this is in the GitHub repository, which there's a link to at the end.
10:22
Shimmer uses a handler-based system which allows for one function to be registered for each event, for the purpose of this bot we're only registering two events, but you can always register more as and when they're implemented in Shimmer. But before we have a look at that, let's understand how this code uses what we learned earlier, and what it actually does. Here we create a new Shimmer client, here we use a function
10:45
that wraps around a custom type. The custom type holds both internal data as well as token, intents, and other data you pass in. So we create a function to wrap it, that way you don't have to manage all of that state yourself. Then we pipe that into the
11:02
connect function, where it takes the client and passes that as the first param, and then passes your handlers in as the second. Normally the token should be an environment variable, but for the purposes of this we're just using a string. Finally, we'll tell Erlang to sleep forever so that our actor and supervisor can run in the background, accepting messages from the gateway and passing them to the event loop.
11:26
Now that we know what it all vaguely does, let's revisit the handlers. First we're going to add a handler for the onReady event. All handlers are passed in their event, as well as the client. That way you can use the client to call other methods, such as updating the bot's presence, or sending messages yourself across the gateway.
11:44
On the client, there's no private accesses, so you can access all the internal stuff as well, if you want to add your own custom functionality. The client has its gun connection and all that other stuff in there as well, so you can adapt that as you please.
12:01
Let's quickly zoom into the handler and explore that. Here you can see the event in this case is an onReady event, which provides us crucial information, and as I said before, there's the client that we have just spoken about. The Gleams Accessor syntax we learned about earlier makes it easy to access
12:21
fields within the types, even when they're two levels deep. As you can see here, we're accessing the user's ID, which is in the user field of the event, and then we're printing it to the console using the standard library's IO. We can then make this into a function, and then we can pass that into our onReady handler.
12:40
That way, we can have the functions in multiple different files and import them from across the project to keep everything tidy. Let's move on to actually receiving some messages and sending some responses. When we receive a message, we get the onMessage payload as our event. This contains information about the message itself,
13:01
as well as the guild ID mentions, the message content, and other variables. For now, we're going to assign the content to a variable for ease, but we can always collapse that into the case statement we use later on, if that isn't something you need. Let's have a look at how we're going to use our pattern matching to match against the content.
13:21
Using Gleam's powerful pattern matching, we can check it as a desired prefix, and then we can extract the part to the right of the prefix into a separate variable. And if not, we can take the message out itself, and we can just print that for easier debugging for now. Let's say we want a specific command, though. We could either add another case statement onto that, or we could just edit it so it's exclamation mark,
13:42
and what we want is the string of pattern matching against. Let's say, for example, you wanted some arguments, though. You could put the two together, and you could have your prefix with the command, and take all of the arguments out separately to then pass and manage them. Now we'll match against a specific command, and in the response, we'll use the message send function
14:04
to reply to the user by sending another message. And as before, we can use the handler's builder to add this in as a function, and the bot should be done. Now you have a basic ping pong where you can send and receive messages using basically everything you learned from the instruction earlier.
14:24
The full code, as I said earlier, was available on the GitHub as well, if you want to have a look and take a deeper dive there. Just to recap, at the start of the talk, we went over some Gleam syntax. Before we get ready on our exploration of Shimmer, we found out how the Discord's gateway worked on a high level, and how to leverage Gleam OTP,
14:42
and how Gleam OTP is leveraged within Shimmer for Actors. Thank you very much for listening, and if there's some QR codes to the Gleam website, as well as the Gleam Discord, if you want to talk there, and if there's any questions, I'm happy to take them if I have time.
15:06
So there's time for questions. You showed the tuple access syntax, which was tuple.0, tuple.1. Does that mean that if you use a record, or whatever it's called,
15:24
can you still use 0 as a key? Or is that not... If you use a custom type? Yeah. No, when you use custom types, you have to use the keys you define in the custom type to access them. The index syntax is only available for tuples.
15:42
Question there. I have a question about the handlers on the library, and about Gleam, I guess. When I'm writing the handler, do I know what type of the event is, and the client by the time of writing?
16:01
Yeah, so when a Gleam project is put onto hex, we produce hex docs, and they're all documented there as well, so the types are on hex docs you can look at, and also Gleam has an LSP built into it, which is going to give you the information in your editor. Ah, okay.
16:22
Hello. If you're used to Elixir, what are the things that you would miss in Gleam? Is there a big overlap? It has most of the features you're used to, along with your type safety. The only difference would be in Elixir, you can define multiple modules in one file,
16:41
whereas in Gleam, that's not really something. Modules are files themselves. I guess that's the only thing I could think of off the top of my head. All right, thank you. No worries. Is there macros as well? No, we don't have macros right now, but there has been several discussions about how we want to do them, and what they're going to be like, so there's potential for that in the future.
17:05
Any more questions? Okay. Do you have one? Yeah. I'm sorry. Thank you for your talk. It was very nice. I have one question. I think currently it's version 0.25 of Gleam, or 26.
17:22
0.26, yeah. Yeah, I'm sorry. This week. Are there any big hurdles before plans for 1.0, for example? I believe Lewis wants to get LSP features more properly implemented, but you can always join the Discord and talk there. I think Lewis is probably better,
17:41
but I think we also have a GitHub milestone on the Gale repository, which says what we want before v1. Any more questions? Okay. Thank you, Harry, again.