Photo by Razvan Dumitrasconiu on Unsplash
Getting started with Grain by examples
Part 2: OMG! No Class! 😮
Warning: this post is a kind of tip found this morning when I woke up. The sample code I'm going to present may not be good practice, but it will give you an idea of the capabilities of the Grain language.
🖐️ Requirements: read the previous post: k33g.hashnode.dev/getting-started-with-grai..
Seventeen years ago, I was programming in C#, then switched to Java and finally to JavaScript for real in 2005. My biggest surprise was the absence of a class in JavaScript (I even used CoffeeScript to try to compensate). Eventually, I got used to coding without classes, and now even in Java, I don't use inheritance much.
So there is no class in GrainLang, but there are Records 🎉. However, no method can be ported to Records 😢, as it is possible in GoLang, (for example, see: gobyexample.com/methods). In fact, by using the functions (closures), which are types, I achieved my goals (remember: functions are a first-class citizen in GrainLang).
I want a Human structure with a method!
Here is my code snippet:
record Human {
mut firstName: String,
mut lastName: String,
mut sayHello: () -> String // 0️⃣
}
let newHuman = (firstName, lastName) => { // 1️⃣
// initialise
let humanInstance = {
firstName: firstName,
lastName: lastName,
sayHello: () => {"default"}
} // 2️⃣
let sayHello = () => {
"👋 Hello, I am " ++ humanInstance.firstName ++ " " ++ humanInstance.lastName
} // 3️⃣
humanInstance.sayHello = sayHello // 4️⃣
humanInstance // 5️⃣
}
let jane = newHuman("Jane", "Doe")
let john = newHuman("John", "Doe")
print(jane.sayHello()) // 6️⃣
print(john.sayHello())
jane.firstName = "Janny"
john.firstName = "Johny"
print(jane.sayHello())
print(john.sayHello())
0️⃣: The type of the field is a closure
1️⃣: I use a closure to define a constructor of
Human
(a kind of factory).2️⃣ & 3️⃣: I need to initialise the record instance and the
sayHello
field first. Then, as the record instance exists, I will be able to use a reference to it (humanInstance.firstName
andhumanInstance.lastName
) inside the closure (3️⃣).4️⃣:
humanInstance.sayHello
is mutable so that I can change its value by the new closure.5️⃣: The constructor returns the record instance
6️⃣: We can use the
sayHello
method on everyHuman
record instanceCompile and run the code, you will get:
👋 Hello, I am Jane Doe 👋 Hello, I am John Doe 👋 Hello, I am Janny Doe 👋 Hello, I am Johny Doe
That's all for today 👋. As I said, I don't know if it's a good idea to code this (and I'm probably making functional programming purists scream 😭 - sorry for that 🤭), but I like the flexibility of Grain.
See you soon for the next episode 😍.