[This episode is sponsored by Hired.com. Every week on hired they run an auction where over a thousand tech companies in San Francisco, New York, and L.A. bid on Ruby developers providing them with salary and equity upfront. The average Ruby developer gets an average of 5 to 15 introductory offers and an average salary offer of $130,000 a year. Users can either accept an offer and go right into interviewing with a company or deny them without any continuing obligations. It's totally free for users. And when you're hired, they give you a $2,000 signing bonus as a thank you for using them. But if you use the Ruby Rogues link, you'll get a $4,000 instead. Finally, if you're not looking for a job but know someone who is, you can refer them to Hired and get a $1,337 bonus if they accept the job. Go sign up at Hired.com/RubyRogues.]
[Snap is a hosted CI and continuous delivery that is simple and intuitive. Snap's deployment pipelines deliver fast feedback and can push healthy builds to multiple environments automatically or on demand. Snap integrates deeply with GitHub and has great support for different languages, data stores, and testing frameworks. Snap deploys you application to cloud services like Heroku, DigitalOcean, AWS, and many more. Try Snap for free. Sign up at SnapCI.com/RubyRogues.]
[This episode is sponsored by DigitalOcean. DigitalOcean is the provider I use to host all of my creations. All the shows are hosted there along with any other projects I come up with. Their user interface is simple and easy to use. Their support is excellent. And their VPS's are backed on solid-state drives and are fast and responsive. Check them out at DigitalOcean.com. If you use the code RubyRogues, you'll get a $10 credit.]
AVDI:
Hey, welcome to the Ruby Rogues Podcast. I am Avdi Grimm and with me today is Jessica Kerr.
JESSICA:
Good morning.
AVDI:
And joining us is a very special guest, Erik Michaels-Ober.
ERIK:
Hello. How's it going?
AVDI:
Doing good here, doing good. And I think today we are here to talk about the Crystal programming language.
ERIK:
That's right.
JESSICA:
Episode 248.
AVDI:
Is that what it is? Oh wow, we're creeping up on 250. So Crystal. I've messed around with it.
Jessica, have you messed around with it at all?
JESSICA:
No, but I saw Erik give a talk about Crystal at PolyConf. So, I know it's kind of like Ruby but fast.
AVDI:
[Chuckles] Erik, how would you define the Crystal programming language?
ERIK:
Yeah, fast is definitely part of the sales pitch for Crystal. And so is 'like Ruby'. I would say it has a lot of the same design goals as Ruby. And as a result it has a very similar and familiar syntax to Ruby, if you're used to Ruby. So, that's kind of the starting place. But it's not absolutely identical to Ruby, although some Crystal programs are valid Ruby programs and vice versa. So, you can just run Ruby programs, simple ones, through the Crystal compiler and they'll just compile. And it will be faster because it's a compiled language and it can do certain compile time optimizations that Ruby can't do. So, that's one of the nice features.
And then one of other nice features which we don't talk about so much in the Ruby community because Ruby is such a dynamic language is that Crystal is statically typed. And I can talk a little bit about my history with statically typed languages and I'd be curious to hear your experience. But maybe this will sound familiar to you or some of your listeners. So, one of the first languages I was introduced to was C++ or Java. I guess that was in high school, just because those were the language that the college credit computer science exams were given in. So, all the books were written around C++ and Java. And those were the languages that were taught and those were two of the first languages I learned. And of course those are static languages.
And I think that just sort of continued on into college. I think most universities teach Java or C++ or C or one of those languages, a statically typed language. And then sort of once I got out of college and gone into the real world, the first company I worked at was using Perl then we migrated to Ruby and I sort of never looked back, doing web stuff, at statically typed languages after that. I've been doing just dynamic web programming, backend web programming since then, mostly. Or dynamic frontend or backend web programming.
So, a lot's happened I think in the last 10 years or so around statically typed languages, particularly with type inference. So, all those type annotations that you might remember from the last statically typed language you programmed in, you don't need those anymore. So, Ruby, Crystal rather, is statically typed. But as I mentioned earlier there are valid Ruby programs that you can just put into Crystal. And Crystal will figure out what all the types are. And that's not true for all programs. There are some cases where you need to put in type annotations so that the compiler can figure out what's going on and how to make certain optimizations.
But in general I would say statically typed programming languages have come a long way in the last 10 years. And this is not just with Crystal. There's a bunch of new programming languages with great type inference. Rust and Go for instance. And so, I think this generation of programming languages gives you a lot of the sort of programmer efficiency that was one of the design goals of Ruby, as well as computer efficiency in that the code can execute really fast because it can take advantage of a lot of the compile time optimizations, as well as type safety, which is nice.
And the pitch for type safety I think for people who are used to programming with more dynamic languages like Ruby, I would say one of the disadvantages of a dynamic language like Ruby is that you can change anything from anywhere and you have this duck typing system. So, a lot of the tests that you're writing are to make sure that given a certain input the output is of a particular type. If you're using RSpec you'll say something like expect that the result is a certain class or something, right? And having a static type system basically will enforce all of those checks for you at compile time. So, it's basically just like writing those types of tests but it's a feature that's built into the programming language. And it makes sure that, it just gives you a little more safety that the bad things don't happen and that prevents whole classes of errors.
So, a very common example of that is null pointer exceptions, what you see in Ruby as no method error where it says undefined method, whatever, for nil. You don't get those types of errors. That's a very common class of error in Ruby. And you don't get those types of error at runtime with Crystal. You get those in compile time. So, you can basically detect those errors more early. And you don't even have to write any tests to do it. The language just does that for you. So, I think that's quite a nice feature.
JESSICA:
So, Crystal's type inference distinguishes between a certain class that you're supposed to return versus nil?
ERIK:
Yeah. So basically, it has a really cool feature called union types. So, it's not a very strict type system in that way. You can basically say this is an array. You can say this is an array of integers. But you can basically say it's an array of integers or strings or characters or the nil type. But then let's say when you try, let's say you take something out of that array and then you try calling a method on it, each of those types needs to respond to whatever method you call. And if there's some type that doesn't respond to that method, then you'll get a compile time error.
So for example, if you take something out of that array that might be strings, characters, integers, or nil, and you call 'dot nil' on it, that's fine because each of those types of objects responds to 'dot nil'. But if you try calling a method that only strings and characters respond to, then you'll get an error. And what's very cool is that if you say inside of a condition, if you say 'if that character or that element of the array dot nil' or you can say if it's not nil for example, if that's true then inside of the scope of that conditional you can call methods on all… basically it will take the nil out of the union type. It knows that that variable is no longer nil. And then, so that's how you can deal with values that are possibly nil. But if you forget to do that, if you forget to put in that nil check, then you'll get a
compile time error.
AVDI:
It's interesting how this is experienced as a programmer. I'd say it almost feels a little bit like duck typing in advance.
ERIK:
Yeah. That's a good way to describe it, like that.
AVDI:
It's similar, for anyone who's done C++ work in the past, it's a little bit similar to working with C++ templates where the compiler doesn't really care what type you put in a template slot. It just looks through to see all of the methods that are going to be called on that type, or all the functions that are going to be applied to it, and makes sure it has… it just checks to see that it has an implementation of those functions for every single one, for the type that you choose. And so in a sense, it's still kind of duck typing because it's not looking at, “Oh, does this implement some defined interface?” It's just saying, “Does the type or types that we're using here, do they all include the methods that we're going to be calling?”
ERIK:
Exactly.
JESSICA:
It sounds a lot like Clojure's core.typed because it's a lot smarter in this sense than the Java type system, which Java's like, “Oh no, I can use that for anything.” Thanks, Java. [Chuckles]
JESSICA:
And also [chuckles] the Crystal and core.typed does this too, it's like aware of the meaning of the code in certain situations like that nil check.
ERIK:
Yeah, exactly. So, I think it's worth talking about not just the benefits of having a more static language but also what are perceived as some of the costs or disadvantages of that.
And one is that you just, you lose a lot of the dynamic features that you might be used to in Ruby. But not all of them, just some of them. So for example, you don't have send in Crystal. You don't have method missing in Crystal. And yeah, so there are certain constraints like that where…
JESSICA:
Do you have monkey-patching?
ERIK:
You have open classes. And so, you do have monkey-patching in that sense.
JESSICA:
Ah.
ERIK:
But everything still has the type check. So, you can basically… and that's actually to me, that's one of the redeeming qualities of Crystal is that you can basically… like as an example, because you don't have send you can't call classes that are private by default. Because in Ruby that's your escape hatch if you want to call some private method, you can just use send to do that. In Crystal there is not a way to do that. But because you have open classes you can actually reopen that class, mark that private method as public, and call it that way. So, if you really need that emergency lever, you can do it.
But I think what it does is that actually encourages better public and private interfaces. And if you find yourself opening a class and setting it public, what you might want to do instead is just submit a pull request that makes that method public for example, or have a conversation with the developer of that library that you're using and say, “Hey, I need some sort of public interface that does this thing that this private method does. Let's think about the best way to implement that.” So, I think it's nice in that it can do the types of dynamic programming in that sense. It has open classes. You can do certain monkey-patching like you can in Ruby and it gives you some of those levers. It puts you, the programmer, in control. But it also gives you a bit more safety. So, I think that's nice.
The other thing I would say about that is I think when a lot of us first discovered Ruby we went pretty crazy with meta programming and a lot of the dynamic features. But it had DRY I remember being one of the big mantras of Ruby. People would always say, “Oh, don't repeat yourself.” And if you're defining 10 methods that all do more or less the same thing, instead just find those methods dynamically at runtime. And Sandi Metz actually wrote a great blog post recently. It was based on her RailsConf 2014 talk. And in there she says basically that duplication is far cheaper than the wrong abstraction.
And I think that's something that we as a Ruby community have come to learn slowly over the past 10 years or so where having methods like the Active Record finder methods, find by name and email address and this, that get defined at runtime when you call them via method missing, maybe aren't such a great idea. And as trendy and interesting as those were in the early days of Ruby, I think we've actually, the trend has actually gone back towards more of a static style. And just because Ruby has those features and just because you can do that doesn't mean you have to. And that type of code where everything is passing through the same method missing method definition, that can be really hard to debug and pretty confusing, hard to grep for those sort of things.
But Crystal does have a macro system. So again, you can… that's one of the redeeming qualities if you like writing things dynamically or defining 10 methods at once or something like that. You can write a macro for that. So again, it's a little bit safer. The defaults I think are a little bit… they don't encourage you as much to do that type of programming. But there are ways to do it if you need to.
JESSICA:
I want to come back to the macro system. But first, in the sense you described, does the Crystal type system and type inference, does it represent the learned wisdom of how to write maintainable Ruby that we've gathered over the years?
ERIK:
I think that's a big part of it, yeah. As anyone who's written tests for a program, you're probably… one of your assertions is going to be that the thing is of a particular type. And if you can just take that and build that into the language, the return value or even the input is going to be of a particular type, and if you can make that a language-level feature rather than something you always have to check for, that can be quite valuable and also can yield really big performance optimizations.
So, just as an example, if you have a typed array, if you know that an array can only contain integers, then you can allocate a fixed amount of memory for each element in that array. And so then when you want to index into that array, let's say it's an array of a million elements and you want to get to the hundred thousandth element, well if everything in that array is a different sized object you have to basically traverse through to figure out where the hundred thousandth element is. Where if you know it's an array of int 32's for example, then you can just multiply 32 times your index and jump right to that position in memory then read out 32 bits and that's the integer. So, certain performance optimizations like that are possible in a statically typed language that aren't possible in a dynamic language. So, you get both the safety of types as well as certain performance optimizations at compile time.
AVDI:
You mentioned a couple of other languages which are comparable in some ways to Crystal, Rust and Go. And I think it's safe to say that at least at this point those have, they have a lot more eyes on them and a lot more press right now. Are there features that for you make Crystal compelling over Rust or Go?
ERIK:
Yeah, I would say first of all if you're a Rubyist you don't really need to learn a new syntax, or I should say the learning curve is much, much faster for Crystal than for a language like Go or Rust. I would say both of those languages have a C lineage where Crystal's syntax really is a direct descendant of Ruby which has a lineage that can be traced back to I guess Lisp and CLisp and Smalltalk and also I guess going back to ALGOL and languages like that. But it has a different syntax, a different feel, and I would say different design goals. It's really optimized for developer happiness and developer productivity in a way that I'm not sure that those were explicit design goals in Rust or Go for the same way that it was in Ruby and Crystal. So, it will feel very familiar for a Rubyist. It should be easier to learn. And you get a lot of the same benefits. And that said…
JESSICA:
And some of your Ruby programs will just port?
ERIK:
And some of your Ruby programs will just port, but some of them won't. And I'll actually talk about some of the specific differences between Crystal and Rust, because I really like them actually. A lot of the things… there's not that many things that I don't like about Ruby. But the few things that I don't like about Ruby have been fixed in Crystal in my opinion. So, it's definitely inspired by Ruby but it also takes features from other modern languages that have been invented over the past 10, 20 years.
So for example, it takes a feature that I think originated in CoffeeScript where if you want to have a parameter that you want to make an instance variable, you can just put the at sign in the method definition. So, you can just say 'def at foo' instead of saying 'def foo'. And then the first line of your method you say 'at foo equals foo'. Maybe that appeared somewhere before CoffeeScript but that's in the language. So, that's quite a nice feature and saves you time.
Another thing that Crystal does, it sort of adopts this Python philosophy that there should be one way to do things, which Ruby doesn't have. I think Ruby because it has a sort of Smalltalk and Lisp dual lineage, there's almost two names for every single method in Ruby. So, I'm thinking of a lot of the enumerable methods. You can say map or collect. You can say inject or reduce. You can say find all or select. I understand why Matz did that because he wanted to appeal to people who are coming from both Smalltalk and Lisp and have the way they think about things just work, have those method names just work. But Crystal is actually opinionated on those and doesn't alias those. It just defines one canonical method.
And maybe that makes it a little bit harder to write code. If you're used to writing it one way you have to learn the other way. But it makes it a lot easier to read code and to teach people to program. Because when they're reading they don't have to learn both names for each method. Hey, there's this thing called map but some places you might see it written as collect. You don't have to learn the two names for everything. So, I think that's really nice. And again as I said earlier, if you want to add those aliases, you can just add them in yourself. If you'd rather call it collect, you can just define a one-liner alias and call it collect everywhere, because Crystal does have open classes in the same way Ruby does. But it leaves those decisions, like if you want to create those aliases you can do that.
But to me when you're designing a language, part of the role of the designer is to make decisions. That's the main role of a designer. And any time the designer doesn't make a decision, any time they say, “Let's just have both,” that hoists the decision up to the user, from the language designer up to the language user. So then the language user, every time they type map or every time they want to perform a map they say, “Do I type map or do I type collect?” They have to make that decision versus the language designer making that decision for you. So, I really respect that decision has been made in Crystal.
Another example of that is Crystal has made a decision about double quotes and single quotes, which is that double quotes are used for strings and single quotes are used for characters. And to me, that's first of all much more natural than Ruby's question mark character syntax which I never really got. And again, it just makes it so that it's easier to write idiomatic code. The compiler will actually prevent you from using single quotes around a string. And everyone does it the same way, so code sort of looks more uniform and is more readable and it just saves people time from having stupid pointless arguments about whether you should use single quotes or double quotes or when you should use them or whatever. And again, because it's compiled there's no performance penalty for one or the other, using single quotes or double quotes.
JESSICA:
If I had a bunch of Ruby code and I wanted it to conform to some sort of standards, could I use the Crystal compiler as a linter?
ERIK:
I wouldn't recommend that. [Chuckles] And yeah, I would say just use Rubocop for that. Rubocop is like my go-to Ruby tool for enforcing…
JESSICA:
But it doesn't do typing.
ERIK:
That's true.
AVDI:
Yeah, but the Crystal compiler is going to flag a whole bunch of stuff in your Ruby code that you don't care about in Ruby code.
ERIK:
Yeah.
AVDI:
Any time it can't adequately infer a type for something where it needs to infer a type it's going to blow up.
JESSICA:
But the type annotations in Crystal, where do they go? What do they look like?
ERIK:
Yeah. So for example, if you have an array and you say 'a equals one, two, three' it will type that array as an array of integers, int 32 specifically. And if you say 'a equals and array of one, and the string hello' then it will create an array of this union type, integer int 32 or string. But…
JESSICA:
If I want to specify that…
ERIK:
Let's say you have an array that is empty. You just want to initialize an empty array. Then you have to say what type it is so that Crystal knows. So, the way that you can do that is you just say 'a equals array square bracket, open square bracket, close square bracket, and then the keyword of' O-F. So, you just say 'array of int 32'. And if you want to define a union type you can say 'array of int 32' and then pipe is the syntax for union type. So, you can say 'int 32 pipe string' for example. And of course you can use any custom defined classes that you want there as well not just the built-in ones.
JESSICA:
What about function types?
ERIK:
So, that's how you do that. And if you want to sort of override the type inferencer, so you say 'a equals one, two, three' but later you want to be able to push strings onto that array, you can say 'a equals array one, two, three, close array of int or string'.
JESSICA:
What about the type annotations for functions like the return types and the parameter types? What do those look like?
ERIK:
So for parameters, you just specify those with a colon, which again is incompatible with Ruby syntax, specifically with keyword arguments. But basically you can just say 'this parameter colon this type' and it will enforce that for you.
AVDI:
Speaking of keywords, have they rolled that in yet?
ERIK:
I think because… keyword arguments you're saying specifically?
AVDI:
Yeah.
ERIK:
Yeah, I think it's not because it's not compatible with the syntax that they chose for annotation the types of parameters. But they might build it in the next version. So, it's actually probably worth talking about the history of Crystal and its development as a language.
JESSICA:
Goodie.
ERIK:
So, Crystal was originally implemented in Ruby. And then basically that version of the compiler was thrown away and re-implemented in Crystal. So, it's completely self-hosted which is another great feature of the language that if you want to hack on Ruby you have to write C code. If you want to hack on Crystal you can write Crystal, which you probably already know. What that also means is that there's a bunch of… Crystal has everything you need in it to make a programming language, sort of by definition. And there are pointer types and things like that which you never need to use if you don't want to. But they are a part of the language. So, that's pretty cool.
But it's actually in the middle of a third rewrite now, so a third reimplementation. And I think they're reevaluating some of the trade-offs they made about annotations versus inference and trying to optimize the performance even more, even though it's already really fast. So, you can read about that. There was a blog post right around Christmas last year that talked about, announced the rewrite and talked about what their design goals for it were and why they're doing it. But that's the state of it now. And I think in the process they'll resolve some of the conflicts between things like keyword argument syntax and type annotation for parameters. But in general you don't have to… because the inferencer is quite good you don't actually have to do annotation of parameters at all if you don't want to. It's really optional.
AVDI:
Yeah, yeah. That's good to point out, is that it's not like you have to go through adding types to every method.
ERIK:
Exactly.
JESSICA:
But you can and then you'll find out if you're getting the wrong thing.
ERIK:
Exactly, yeah.
AVDI:
Yeah. Well, you'll find out either way. I think return values is probably a more interesting case because there you can, I believe you can specify a return value and then it'll start saying, “Wait a second. This function doesn't return the thing that you said it was going to return.”
ERIK:
So, the way that that actually gets enforced is based on what you do with that return value. So, it doesn't actually enforce that at the method level. If you take that return value and you try to pass it into something that doesn't expect something of that type, then it will complain.
JESSICA:
But I love that you can add the annotation to the return value, because sometimes it's like really hard to narrow down where a bug is. And you might find it much later that you're calling a method on a type that doesn't have that. And if you add the return value to the functions then you find out earlier when you created the value, whether it's the wrong type, or whether there's any path in that function that could cause it to return nil.
ERIK:
Right.
AVDI:
There's some upheaval going on right now in the design of the language as a result of all this, of some of the implications of all this type inferencing. Do you want to talk about that a little bit?
ERIK:
I'm not sure specifically what upheaval you're referring to.
AVDI:
Oh, okay. Well, so up until now one of the little downsides of the way the type inferencing worked was that the compiler had to be able to see the entire program. And by entire program I mean every single line of code that goes into it, including all libraries, because it had to make sure that it could trace down every possible path. This has some unfortunate implications for compile times once you start getting into non-trivial programs. And that's been one of the things hanging over the language as it matured, is that it's young, all the programs are very small, but as they start getting bigger that starts to become an issue. And up until recently as I understand it, it really didn't have the features it needed to do any kind of linking, because there was no kind of definite… there was no interface definitions or anything like that.
ERIK:
That's exactly right. You can't… it doesn't do incremental compilation. And I think again, that's one of the big goals for this new rewrite of the language, is to basically make compile times faster and allow you to write bigger programs. That said, the Crystal language itself which as I mentioned is completely self-hosted, completely written in Crystal, it's about a 40,000-line codebase and it compiles in under a minute. And most really simple files like scripts and things like that will actually compile and run faster than the equivalent Ruby program, which needs… there's the startup time of the Ruby interpreter and then it's interpreted. So, Crystal can actually compile and run a program faster than Ruby can interpret and run a program, in the case of relatively small programs. And for larger programs, there's definitely, yeah that's definitely an issue that they're addressing, the creators of the language are working on.
But I would say a lot has happened in compiler technology over the past few years. And if you look at modern compilers like the Go compiler for example, it's really quite fast. And I think that's not really slowing people down so much.
AVDI:
Yeah. Although I guess Go had incremental compilation built into it from the beginning.
JESSICA:
As a Scala developer I can say that slow compile times are a serious negative.
AVDI:
[Laughs]
JESSICA:
Especially when you come from Ruby and you're used to that super quick test time turnaround. Because you've got to compile before you can test and when your tests take 10 seconds that is a big difference from half a second [inaudible].
AVDI:
And that's actually… something related to what you just said is another potential issue which is that, at least last I checked Crystal does not have a REPL, does it?
ERIK:
Actually it sort of does. So, there are a lot of people working on competing ones at this point. I think the latest one is called ICR, so like IRB but it's ICR. That was done by Grey Blake and posted to the mailing list something like two weeks ago. It's quite new. But yeah, I would take a look at that. Again, because of the way Crystal works basically every time you type a line into the REPL it has to recompile every previous line you've typed. So, if you have a big buffer then that's not going to be great. But you can install it and it works. And I think there are certain edge cases that it can't handle. But for just basic testing out code and things like that, that's one project. And there have been other attempts at it as well. I think that's the newest one. And it's the one that's gotten the farthest. And it's definitely a challenging problem to have a REPL for a static compiled language. But it's definitely possible and people are working on that now.
And in general I would say one of the cool aspects of Crystal is it's just such a new language that things like a REPL don't exist or just barely exist and you can be either the creator of the REPL or a very early contributor to it. And it's just really early days. And I think of the early days of the Ruby community and heroes of mine, pioneers of Ruby, people like Jim Weirich who created Rake and gave us this amazing tool that now basically everyone in the community uses. In Crystal a lot of that tooling doesn't exist and if you're interested in coming to a language early in its development you can be one of those pioneers and develop that early tooling, things like REPLs and runners and things like that.
AVDI:
Yeah.
DAVID:
Well, for a statically compiled language, isn't the REPL a code, compile, test?
JESSICA:
Hello David.
ERIK:
[Chuckles]
DAVID:
Oh and by the way, if you wanted to change the number of panelists on a podcast would you have to start the podcast over and get a new copy of it or…
AVDI: [Laughs]
DAVID:
Would you just mutate it halfway through the call?
ERIK:
You can mutate it. It's not closure.
DAVID:
Excellent, excellent.
ERIK:
Yeah.
AVDI:
And now welcoming special surprise host, David Brady.
DAVID:
Hi there.
JESSICA:
Now what was your question?
ERIK:
So yeah, I'm not sure I understood your question, David.
DAVID:
Okay, so when you stay statically typed compiled, I obviously think C, right? And there is no REPL for C. The REPL is code, compile, test. I want to say let's throw out everything we've learned in the last 16 years but that's way too dismissive. What I mean is for statically compiled, if you're going to change something on the fly that is alien to the way the language works, right?
JESSICA:
Not anymore. [Elm] has a REPL and it doesn't get more statically typed than Elm.
ERIK:
I think basically the way it works is every time you hit enter in the REPL it basically goes back to the top of everything you've written and recompiles it to see what's changed. But because compilation is so fast for short programs, you're basically able to do that and get the feel of a REPL, that real-time interactivity.
DAVID:
That's so awesome.
JESSICA:
Ah, so don't type 40,000 lines into the REPL.
ERIK:
Right, which I think is an anti-pattern anyway.
JESSICA:
[Chuckles]
ERIK:
But yes. That's' what files are for. But yeah, for just experimentation and figuring out… I normally use a REPL to figure out one line of code or a block of code.
DAVID:
Yeah.
ERIK:
Like I need to do some mapping of something to something else and get it into the right data structure. It's great for that.
AVDI:
And Erik was talking about the feel of getting into the language at the ground level. And I want to second that, particularly with regard to Crystal. And I hadn't really thought about this until you started talking about it. There are a bunch of other interesting new languages right now. But a lot of times languages come out of big companies like Google or big organizations like Mozilla. And the fun thing about a language like Crystal is that it's being done by a very small group of core developers. It's not being launched at 1.0 by a big corporation or organization. So, it really is kind of a neat small town feeling if you go in there and decide to get involved.
ERIK:
Totally. And you can actually have a pretty big impact on the development of the language. So, just to be clear, I'm not one of those core developers on it. I'm just an early adopter and evangelist for it because I think it's cool. I've given a couple of conference talks about it and just experimented with it in my free time. But as an example I just started using it and there were certain things where I thought, “Oh, this should work,” and it didn't work. And I opened an issue and I found the developers of the language to be super nice, which I think is a big value in the Ruby community. You have nice language creators. They seem incredibly nice, responsive, thoughtful. I was like, “Hey, I tried doing this. I expected it to work. It didn't work,” and they either explained to me in the nicest terms possible why I was wrong [chuckles] and that it really shouldn't work…
DAVID:
[Chuckles]
ERIK:
and this is why, or they actually changed. And they were convinced that this should be a feature. And so, I in a very small way had an impact on the development of the language at an early stage.
So, one example of that is I tried to concatenate a character onto the end of a string. And that didn't work. So, I had 'foo' and I tried adding 'foo the string' and I tried adding 'd the character' to make food. And it said there wasn't an overload for the string plus operator with characters. And originally they said, “Actually, that's a feature because they're different types.” And I was like, “Yeah, but in the same way that you can add integers to floats then expect to get a result, you should be able to add strings and characters even though they're different types. They're similar in a certain way that you would expect to be able to concatenate them.” And yeah, they basically accepted that argument and now you can concatenate characters onto the end of strings.
DAVID:
Nice.
ERIK:
So yeah, so little things like that. It wasn't a part of the language. We had a short discussion on GitHub, and now it's part of the language. And I just feel like Ruby has been around so long. There are so many programs and existing code written in Ruby, that the language has kind of ossified to a point where Matz is afraid to make any sort of significant changes because it will break so many production applications that large corporations have invested lots of time into their production Ruby systems. And Matz wouldn't want to break that and cost all those companies lots of money.
And Crystal just doesn't have that constraint. It can be much more fluid, the language. It's not 1.0 yet so there are no promises, semantic versioning promises about what will break between versions. And in practice a lot of things do break between versions, which is sort of both good and bad, right? It's bad if you're trying to run a business on it. But it's exciting if you want to kind of have an influence on the language and make some big changes to it. You can still do that.
DAVID:
Erik, are you really telling me that we're going from a language that is the poster child for 'break all the things' and we're going to static typing and pre-compiled languages in order to get more crazy?
ERIK:
Well, I think to get things right.
DAVID:
[Laughs]
ERIK:
May be the argument, but yeah.
DAVID:
Yeah. That is so awesome.
ERIK:
Yeah, because there are a lot of things about Ruby that most people agree, if we had thought of those 20 years ago we would have fixed it. But now so much code depends on that being the way it is that changing it would break too many things to make it worth it. So yeah, there's a chance to get those things right. And I think the authors of Crystal have recognized a bunch of those flaws in Ruby and fix them. But for the ones they haven't, you can come in and give your two cents about that as well.
DAVID:
Yeah.
ERIK:
So for me, that's a very exciting time in the development of the language.
DAVID:
That's fair. That's fair. There are a lot of people who would argue that Ruby is like… I'm going to go back and tell our DevOps people, our infrastructure people that Ruby is considered stable. And I'm going to Instagram their face and send it to you. It'll be fun.
ERIK:
Well, the language specification is quite stable.
DAVID:
Yeah.
ERIK:
From 1.8 to 1.9 I would say that was painful. But since 1.9 it's been really smooth sailing. I think people expected the 1.9 to 2.0 transition to break things.
DAVID:
Yeah.
ERIK:
And it didn't break anything. And I think Matz actually took a lesson from the Python community which has had such a struggle transitioning from version 2 to version 3. He saw that as a sort of counterexample of how to evolve a language and wanted to avoid that where the community and the libraries and everything are really split between two versions. And as a result has just been very conservative about making backward incompatible changes since 1.9. For better or for worse, but Crystal is a chance to start over on some of that stuff.
DAVID:
Yeah.
ERIK:
And make really big changes. So actually, one change I would highlight from Ruby and one syntactic difference between Crystal and Ruby is their 'to Proc' syntax. So in Ruby, if you have a method that takes a block and all the block does is call a single method on that block, am I getting that right? Basically if you have like an iterator like map or something like that, an enumerable, and you want to call 'to S' for example on each element in that array, then you can say 'ampersand colon to S'. In Ruby, just as a shorthand for the block, 'map do the pipes, the block variable, and then that same thing, to S' right? So, that's just a shorthand for that in Ruby. But one disadvantage of that in Ruby is you can only do that with methods of arity zero. So, you can do it with 'to S' but you can't do it with modulo for example which takes an argument.
And Crystal actually has a slightly different syntax which instead of 'ampersand colon' it's 'ampersand dot'. And 'ampersand dot', you can put any method after that including methods that have an arity greater than zero. And you can even chain methods together in that way.
DAVID:
Oh wow.
ERIK:
So, you can actually do pretty sophisticated transformations using that syntax. And again, I think that's one of those features where symbol to Proc I actually I think came out of Active Support. It came out of Rails just as a shorthand because Rails was doing that all the time. And then Ruby said, “Oh yeah, that's convenient. Let's add that into the language,” but it wasn't something that was there from the beginning. And I think if it was there from the beginning maybe they would have chosen to design it the same way that Crystal did. But instead it was sort of bolted onto the language afterwards and I think it sort of shows, right? The fact that you can't do it with any method. You can only do it with methods of arity zero. It's kind of inelegant, where in Crystal you can do it with any method and I think that's actually quite a nice feature.
It's incompatible with Ruby because that 'ampersand dot' is invalid Ruby syntax which again to Jessica's question earlier is another reason why you probably wouldn't want to use Crystal as a Ruby linter. Because it would accept a lot of invalid Ruby code.
JESSICA:
Had to ask.
ERIK:
[Chuckles] But it's a pretty cool feature. And again I think just because you have that chance to start over you can get innovative features like that into the language.
DAVID:
Mmhmm. It's neat to see the advantages that you have going from, the disadvantages going from one well established version to another well established version where you're going from nothing to the first well established version, is that yeah you can come in and say, “Hey, let's get everything right the first time.”
ERIK:
Yeah, exactly. And that's actually probably worth talking about as well.
DAVID:
Excellent.
ERIK:
Yeah. So, Crystal right now borrows its threading model from, I guess Go is probably the closest, and gets some inspiration from Erlang as well. So, it uses, there are two concurrency primitives that it encourages using, channels and fibers. And fibers are a little bit different from Ruby fibers. They're more like processes in Erlang. But those are the two concurrency primitives. And they're quite smart in how they schedule the fibers with blocking I/O and things like that. So basically, the concurrency story for Crystal is good I think in the sense that the primitives are right. But not great in the sense that you still only have green threads. It doesn't actually use native threads.
DAVID:
Ooh.
ERIK:
And everything's going to be running in a single OS thread I guess similar to Node. I'm pretty sure that's still a constraint of Node. But people still, from a concurrency perspective I think they've gotten everything right. And from a parallelism perspective, that's more of a feature for the language designers to implement later to get the concurrency running on multiple cores. But as the user, you wouldn't have to change anything in the interface about the way you do things to get things going from concurrent to parallel. It's just a language feature.
AVDI:
Or so we can hope.
ERIK:
Or so we can hope, right. They haven't done it yet. But it's still really early days.
AVDI:
Yeah. That's definitely one of my biggest question marks hanging over the Crystal language is the fact that the concurrency story is still very early days. But yeah, I agree. I think it's going in a good direction. The fact that it's based on a channel and fibers model plus the fact that they're building on the LLVM infrastructure, that suggests to me that what you just said is going to be more or less true, where at some point we'll be able to move over to system threads without too much disruption. Because if you are only using fibers to talk from one process to another, that means you're not sharing memory between processes. That's the big danger that lower-level threading models run into.
ERIK:
Yeah, exactly. And you also brought up the point Avdi that it runs on LLVM. I didn't mention that but I'm glad you did. It's another huge advantage of the language, I think, that it builds on top of this existing very impressive compiler framework. And as a result of that if you're on OS X you can actually use Apple's built-in Instruments app to profile your application for example, just because it's all LLVM bytecode at the end of the day. That's what it's getting compiled into. So, I think that's a pretty cool feature as well.
AVDI:
Yeah, for those…
ERIK:
And you know, it's… yeah, go ahead.
AVDI:
For those who don't know, LLVM is… I guess you could call it a compiler toolkit or a language toolkit, language building toolkit.
ERIK:
Yeah, exactly. And that's what Swift is built on top of.
AVDI:
Right. So, Swift, Rust, trying to think what else, all built on top of LLVM.
ERIK:
Yeah. A lot of modern languages, there's actually some talk of Ruby switching over from YARV to LLVM for version 3.
AVDI:
Yeah.
ERIK:
I've heard sort of murmurs about that.
AVDI:
And actually, a lot of people who are compiling C and C++ programs now are using the Clang compiler instead of the…
ERIK:
GCC?
AVDI:
The GCC compiler, which Clang is built on top of LLVM. So, it's a huge collection of components for building a programming language. And some of the cool things about building on that is that people who build on that, they often find they get a whole lot of optimizations more or less for free, because there are these low-level optimizations that don't care about what language was used to generate the bytecode. But once you have the bytecode the LLVM compiler can just start doing those optimizations. And it also gives a language a really good platform for compiling to many different target platforms. Anyway, I think I interrupted you in something.
ERIK:
No. That's, I wanted to talk about LLVM. So, I'm glad you brought it up. That's cool.
I guess one other thing I was interested in talking about was Crystalshards. So, shards you can think of sort of like gems. And Crystalshards is basically like the RubyGems of Crystal. I would say again, this tooling, the dependency management and stuff like that, is not nearly as mature in the Crystal ecosystem as it is in the Ruby ecosystem. But actually, if you just post a Crystal project to GitHub and you include a shards.yml file in that project, then it will get picked up by the Crystalshards app. And you can see all of the projects that people are building in Crystal.
So right now, there are only 541 third-party libraries. And by default they're sorted by stars, the number of stars on GitHub. But it's pretty cool to see what's out there. If you look through the list, there's a bunch of different web frameworks, some that are sort of trying to be full MVC Rails style web frameworks. So, there's one called Amethyst. There's another simpler framework called Kemal. There's a Sinatra clone called Frank. But there are also some really cool things. So, there's a library called Hoop which you can use to build native OS X apps, Mac apps in Crystal. And this relatively new REPL as I mentioned is there, ICR. So yeah, every day there's a new project popping up.
And the other thing you're starting to see is drivers for different databases and things like that. So, there's a Postgres driver. There's a MySQL driver. There's a Redis driver. So, you can talk to different backends and things like that. So yeah, it's starting to see the language mature and these libraries come about. There's even something called active_record.cr which is basically an implementation of the Active Record pattern in Crystal.
AVDI:
Oh boy, here we go again. [Chuckles]
ERIK:
Take that as you will.
AVDI: [Chuckles]
ERIK:
But yeah, there's lots of interesting things going on, on Crystalshards. So, that's a good way to keep an eye on what's happening in the Crystal community as well as the mailing list. And Crystalshards I think has a Twitter account as well. So, you can just follow them on Twitter and see every time something new is posted.
AVDI:
Yeah, there's also a Crystal Weekly newsletter now.
ERIK:
That's true. Yeah, that's great too.
AVDI:
I'm a big fan of the newsletters that sum up the news of the week.
ERIK:
Yeah. That said, the actual mailing list is pretty low volume.
AVDI:
Yeah, that's true.
ERIK:
At this point at least. So, I actually subscribe to that, not as a digest. I get all the messages and it's not overwhelming. And there are some pretty interesting discussions going on there about the evolution of the language and how it's going. And there's also a great IRC channel that's pretty active. And you can talk to the creators of the language there. So yeah, very open community and lots of ways to engage with it.
DAVID:
Is Crystalshards doing the same thing that RubyGems did when GitHub was really first on the scene or really exploding out where you can't just say, “Hey, I want this to be the memcached shard,” right? You have to say, “This is going to be sferik/memcached or dbrady/memcached,” because I forked your version of it and made a change to it. Are they playing that game or is there a specific way to point to these?
ERIK:
Yeah, so basically it's a little bit closer to the Go model of you just point to a URL.
DAVID:
Oh, okay.
ERIK:
And yeah, so you can basically specify dependencies in a project file. And the dependency manager is actually built-in to the language. So, if you say for example 'crystal deps' that will install all the project dependencies from GitHub in your project. And then what Crystalshards does is it's basically just like a web directory that you can use to find… it's more like, what is it? The Ruby toolkit. It's a little bit closer to that than it is to RubyGems.org maybe. And it's not, again because there's no incremental compilation you can't prepackage gems. So basically, the way things are distributed is just, there's source code and then you basically clone their source code into a lib directory in your project. And then when you compile your project it compiles that in whatever state it is. So, yeah.
DAVID:
Okay.
ERIK:
If you want to clone someone else's Git repo, like if there's a fork that you want to use instead of the upstream mainline repo, you can just do that in your project file.
DAVID:
That was going to be my exact follow-on, is for people that are looking at Crystal… I mean obviously this is going to be very avant-garde stuff that you're not going to just jump into this for well established production stuff. But when you get into big production stuff you start dealing with problems like, “Well, we don't want all of our shards to be public. We want to host them on a private gem server that's inside the VPN.” And if it's just URL-based, then you're done.
ERIK:
Yeah. You just need private Git hosting.
DAVID:
Yeah.
ERIK:
And you can have private repos.
DAVID:
Yeah, that's perfect.
AVDI:
So Erik, what kind of things have you built with Crystal?
ERIK:
So, I guess one of the more popular Ruby libraries I built was the Twitter gem to just basically interact with the Twitter API. And so, I started re-implementing that in Crystal, which was actually really great, really cool experience.
Another thing I meant to talk about was the standard library of Crystal. And it's just a great modern standard library. So, one of the things that's built into it is JSON parsing. And it's now part of the Ruby standard library but used to not be, so there are competing JSON parsers and encoders in the Ruby community. In Crystal there's a standard one and it's great. It's super fast. There are actually some benchmarks that show that it performs basically as well as C++ for JSON parsing, which when you think about modern architectures of service-oriented architectures and different applications passing messages back and forth in some sort of protocol, serial protocol over the wire, JSON being able to encode and decode that quickly is really important.
So yeah, so I wrote a Twitter client, a Twitter API client in Crystal. And I also wrote one for SoundCloud as well, because I was looking at SoundCloud at the time. And those were some early projects. And then I started building a command line interface in Crystal for Twitter. So again, I did that in Ruby. And one of the things that I really didn't like about the Ruby version is that the startup time, if you were doing something that went over the wire that talked to the network that would be slow but it would be slow mostly because you were waiting for the Twitter API to respond which could take a second or two. But if you just wanted the help command that was also slow. And that was mostly because of Ruby's startup time.
DAVID:
[Chuckles] Yeah.
ERIK:
Because it had to interpret the entire program every time you ran it. And with Crystal it's all compiled. So, that's way faster.
And then I also implemented the wc, word count command line utility, Unix utility, in Crystal, just sort of as a fun exercise and experiment. And yeah, one of the constraints was that I wanted to keep it to 50 lines of code and be basically like feature, like POSIX compliant, to be a POSIX compliant wc and 50 lines of code. And so, I did that. And then I compared it to the GCC version which was like thousands of lines of C code.
DAVID:
[Chuckles]
ERIK:
And the performance, the C version is faster than the Crystal version that I built in 50 lines. But if I got rid of that constraint and gave myself a hundred lines, I could probably get pretty close to the performance of the C version.
DAVID:
Wait, so you're fully compliant in 50 lines of code though?
ERIK:
Should be, yeah. It doesn't… there are certain things like the POSIX standard if you read it requires certain internationalization.
DAVID:
Okay.
ERIK:
Like if you have certain environment variables set it should do the output in different languages. But wc is mostly outputting numbers. The only place that wc doesn't output numbers is the word 'total'. So, if you say wc and you give it multiple files, not just one, it gives you the byte count, character count, word count, line count, for multiple files. And then at the bottom it says total and it sums them. So, that total is not internationalized, not localized. So, I guess it's not POSIX compliant in that very small way. But yeah, to be honest I'm not even sure if… yeah, I mean I guess the GCC one has that. It does…
DAVID:
That's wild.
ERIK:
Yeah, all the flags and stuff work. So yeah, I actually read the POSIX specifications for wc and implemented it.
AVDI:
That's super cool.
DAVID:
That's so nerdy. [Laughs]
AVDI:
I want to go do that now.
DAVID:
Yes.
ERIK:
Yeah, and the Crystal, I think I implemented it in such a way that you can basically change one or two lines and it's valid Ruby. And so, when I run the exact same code, I made a bunch of example files for it. If you actually look at the project, it's just called, it's at GitHub.com/sferik/wc.cr. And there's a test directory which just has a bunch of sample files in it. So, there's a blank file. There's a binary file. There's a file with 10 million lines. There's a file that has UTF-8 characters in it, emoji and other stuff like that. And I just wanted to make sure that basically the test suite I wrote using Bats which is Sam Stephenson's framework for testing command line utilities. Basically what it does is it just runs the wc command on your system and then it runs the Crystal wc and make sure they get the same results for a bunch of different examples. So, that was cool.
And then I did some performance benchmarks as well to make sure that… to see how it performed. And the Ruby version which is just a small tweak on the Crystal version… I'm trying to remember the exact numbers of the benchmark. But basically, the Crystal version was two or three times slower than the C version for counting the number of lines in a file with a million lines. And then the Ruby version was 10 times slower than the Crystal version. So again, it was basically the exact same code, the Crystal and Ruby one, just a couple of lines tweaked. So, removing some of the type hints and things like that. So, that was a fun little experiment to do. And yeah, I'd encourage you to look at the code. It's 50 lines of code, including whitespace and everything.
Pretty simple.
DAVID:
[Chuckles] That's awesome.
ERIK:
And it uses Crystal's option parser, standard library. Yeah, maybe I can spend a minute just talking about some of the other cool stuff in the Crystal standard library, because I think that's one of the nice things about again just having a modern language that you're rethinking from scratch.
So, there's JSON parsing, there's CSV parsing. There's XML parsing. But what's cool is there's also markdown parsing. And again, you can have that in the Crystal standard library because markdown is a very popular thing now. I don't think it existed when Ruby was first developed. And as a result of that, it never made it into the Ruby standard library. And there's a bunch of different competing implementations of that. So, it's kind of cool to have just an official one that's written by the authors of the language and is optimized and works very well, is fast. There's a WebSockets implementation in the standard library as well, which is pretty cool. I'm pretty sure that's missing from Ruby. And yeah, things like calculating Levenshtein distance, that's all in the standard library. OAuth and OAuth 2 are built into the standard library. So, just a bunch of things that I think if Ruby was recreated today would be in the standard library but just for historical reasons aren't there. But they're there in Crystal.
So, it also makes it so that you don't have to depend on third-party libraries as much and you can do some really useful things. There's a test library built into the standard library that much more closely resembles RSpec than MiniTest or Test Unit. So, if you prefer that style of testing, that's what's built into Crystal. So, I like that about it. And yeah, also just like I said, Crystal's implemented in Crystal. So, everything that you need to build a programming language is in the standard library. There's pointers and pointer I/O in the standard library. So, you can do some, if you want to so some really low-level programming you don't have to, you can just do high-level Ruby style programming, but if you want to build really low-level systems code in Crystal you could do that.
DAVID:
This is actually kind of exciting. Because obviously when you talk about a Ruby-like language and we say, “Well, it's Ruby but it's compiled,” that kind of thing, the first thing we start talking about are the also-rans. That's the wrong term for that. Also-ran means failed. What I mean is something, I mean also-ran but not in the sense, the political failed sense. You know what Mandy, can you make me not sound stupid here. Actually, good luck with that. [Laughter]
DAVID:
I mean we talk about going from Ruby to a… it's like Ruby but it's compiled, the first thing we think of are the things that are extant in Ruby that, can we port these? Ports. That's the word that I'm looking for. Things that have been ported over. Do we have a Rails clone? Do we have a… like you've ported the T gem over to a T shard or a Twitter Crystal shard and that sort of thing. But once we've established the legitimacy of Crystal as a language, now I kind of want to start looking about where is the extended superset kind of thing. Where are the things that we can go with a compiled language that Ruby historically doesn't do well?
Things like being able to spawn… like the one thing PHP still have over Ruby, the reason it won't die, is that you can fork an instance of PHP with just 8K of RAM because it's a very thin binary. You don't need 128 megabytes to load a new instance of Ruby and Rails and all of the stack on top of it. Is somebody going in that direction with Crystal? Looking for ways to start up a hundred… almost like Erlang style parallelism. Is anybody looking at going towards desktop programming or mobile iOS binary programming, GUI programming? The areas that Ruby has traditionally, I don't want to say abandoned but not really gained the level of entrenchment that we like to see when we want to see Ruby everywhere.
ERIK:
I think so. I don't know. I'm looking at the size of Crystal programs that are running. And most of them, they run so fast I can't even catch them to see how much memory they use.
DAVID:
Yeah.
ERIK:
But I know that the authors of Crystal are doing bytecode level optimization to make sure that Crystal is, like the Crystal code that gets compiled is extremely efficient. And you get all the benefits of leveraging that LLVM compiler toolkit. And the other thing is that Crystal used to not even have a garbage collector. Basically every program just leaked memory.
DAVID:
[Laughs]
ERIK:
Until it finished running. And then they added a really naive garbage collector that seems to work pretty well. It's not great and it's not as mature as modern day Ruby GC. But maybe it's like comparable to where Ruby was with its garbage collector in 1.8 or something like that.
AVDI:
Yeah, yeah.
ERIK:
So, there's a ton of room for improvement. And already if you look at some of the benchmarks, I mentioned earlier this benchmark around parsing large amounts of JSON, Crystal actually performs quite well against C++, not just in terms of time but also in terms of memory usage. So, I think that's quite impressive. And again, I think performance is definitely a goal of the language both speed of developer performance and speed of the computer. But at this point it's still a very young language and there's not that much existing code so that you can actually make pretty big changes to it in the name of efficiency
DAVID:
Nice.
ERIK:
If you need to. But I think it's already quite efficient. And a lot of that, there's still a lot of lowhanging fruit still ripe for the picking on the performance side.
DAVID:
Yeah.
AVDI:
Yeah, I think there's still probably going to be a lot of releases where they just say, “You know what, we turned on this LLVM this optimization and now it's 10 times faster.”
ERIK:
Yeah.
AVDI:
Maybe not 10 times, but some percentage faster.
ERIK:
Right. But we actually spent some time on the garbage collector. I think they basically just took off the shelf garbage collection algorithm and slotted it in. And it basically worked.
AVDI:
Right.
ERIK:
Maybe they re-implemented it in Crystal. But it was basically an existing known quite naive algorithm. And that seemed to be good enough.
AVDI:
Right. So, when I think about the things that I might consider writing in Crystal, what springs to my mind is if I'm looking at something that I might otherwise write in Go but I want to do it in such a way that I don't feel like Rob Pike is glaring at me, I might write that in Crystal. Does that [chuckles] seem fair?
ERIK:
Yeah, yeah.
JESSICA:
[Laughs]
ERIK:
Sounds good to me.
JESSICA:
So, you're saying that Crystal has a different style than Go encourages?
AVDI:
Go, this is one of those things that are probably going to get me in trouble, but Go comes from… if you read the papers around its features and about why it is the way it is and stuff like that, Go can come from a perspective of A, C was basically perfect, it just needed a few things fixed. And B, as a programmer we can't trust you. We can't trust you not to be too clever for your own good. So, we're going to try to make programming as boring as possible.
JESSICA:
That makes sense.
AVDI:
Which I totally understand that perspective. I just don't enjoy it.
JESSICA:
Whereas Crystal is like Ruby is basically perfect if you use it correctly, except now it's faster and safer and also macros.
AVDI:
Yeah. Crystal does pull back from the Ruby perspective a bit. It's clearly not trying to be a Perl style sys admin glue language. And like Erik was saying earlier, they're removing various aliases and things like that where two things or one thing has two different names based on preference. But it still has a lot of that syntax sugar that you expect in Ruby.
ERIK:
Yeah. I think the way I would say it is it has the same design goal as Ruby and that it's optimized for developer happiness. That's definitely one of the design goals and I think that's why they started with Ruby-like syntax because Ruby had that as a goal. And I think it has achieved it better than any other language so that seemed like a very logical starting point. But then I think they also have some differences in philosophy with Matz around what constitutes developer happiness. So, like null pointer exceptions I think do not make developers happy. [Laughter]
ERIK:
So, a type system…
JESSICA:
Yeah, speaking…
ERIK:
Yeah, a static type system is a way to ensure that that will never happen in production. And I think that's one of the trade-offs.
JESSICA:
Speaking of developer happiness, what are the compile errors like?
ERIK:
They're great. Again, this is a huge benefit of anyone who's worked with any LLVM language knows what they look like. So, they have that squiggly green arrow pointing at the error. And yeah, the error messages I think are really well-written and easy to find. I actually on this call, while Avdi was just talking, I tried to compile my wc program on the latest version of Crystal. And there was one small error that I needed to fix. And yeah, basically it was really nice. So, inject again in this culling of aliases, inject was renamed to reduce. And I used inject in my program.
So, the error was 'in source wc.cr line 16, column 16, undefined method inject for array of type int 32' and I was calling that using the symbol to Proc, or it's not really symbol to Proc but the 'to Proc' syntax of 'ampersand dot' in Crystal. So, I was actually calling inject via symbol to Proc. Or I keep saying symbol to Proc but the 'to Proc' syntax. So again, calling inject with arguments and a block. So, that actual line of code was 'columns dot map' and then in parentheses 'ampersand dot inject zero' and then a block 'sum N' and then 'sum plus equals N'. So, doing a whole inject in a 'to Proc' which was pretty cool. Reading code over a podcast I know is probably… [Laughter]
ERIK:
But it's only 50 lines of code. Just go read the source code and you'll see. I think… it has quite a… if you're a Rubyist I think it will look maybe not identical but very familiar and it will make sense almost immediately.
AVDI:
Yeah. And you've got all that Ruby syntactical goodness that we've come to expect like blocks and like the thing that's similar to symbol to Proc that you're talking about, which is actually a bit more powerful than Ruby's version. And all those little niceties that they save your typing time. And you feel like, “Oh, I'm not wasting time rewriting the same boilerplate over and over.”
ERIK:
Yeah, exactly.
AVDI:
And if you really want to save some time there's always the macro system.
ERIK:
[Chuckles] Yeah. But you don't have to use it, right?
AVDI:
Right.
ERIK:
I think people who don't like macros talk about how difficult it is to debug in the same way that I was talking earlier about how method missing can be difficult to debug. And so, I think of macros as, it's like one of those tools that's built into the language so that the language designers can build a nice language for you because it's a self-hosted language and they needed macros. Like for example, the equivalent of attribute reader and attr_reader and attr_writer in Crystal which are called getter and setter, and then the attr_accessor which is called property in Crystal, those are all implemented as macros. And they're incredibly simple macros.
But it's basically like a language feature for the language designers to make things like that for you to use. And you can assume that they'll, as language designers use them correctly because they built the feature. But if you don't trust yourself to use macros you never have to use them. And yeah, it's just something that's there if you want them. But I think a lot of modern languages do have macros. And I think that it's sort of, it's kind of coming back it seems like.
AVDI:
Yeah. Yeah, well I mean every language that didn't have macros wound up, they wound up being re-implemented poorly on the outside of the language.
JESSICA:
As code generation?
AVDI:
Yeah.
ERIK:
Yeah, exactly.
JESSICA:
The macros at least are dynamically adding code at compile time instead of at runtime. It's a little better.
AVDI:
[Chuckles] Yeah. With a macro you always have at least the potential for tools that will actually expand out the macro in your editor. I'm not saying that exists for Crystal yet but it's a thing that exists for other languages.
ERIK:
Yeah, it's possible.
AVDI:
Totally. It should be totally possible where you can hit a key in your editor and actually see the macro expanded out given some arguments.
ERIK:
Yeah, exactly. Yeah, and the macro syntax is just, it's basically like the, what is it, Mustache or Handlebars. It's like the double curly for doing the interpolation in the macros. So, even that's pretty friendly.
AVDI:
Yeah. That actually, yeah that sounds pretty nice.
ERIK:
It looks like a template basically, which is basically what a macro is.
AVDI:
That's nice compared to some of the other macro syntaxes I've seen.
ERIK:
Yeah.
AVDI:
So, is there anything else we want to say about Crystal before we wrap up?
ERIK:
I think that's all I've got.
AVDI:
Alright. Well, if we don't have any more questions I guess it's time to get to the picks. Jessica, do you have any picks?
JESSICA:
I have one pick. It's a very short pick. It is EasyPrompt.net in which you can construct your little Bash prompt of your preference. And I picked my Git branch and I made it yellow and I picked the time of day so I can tell how long ago I typed that thing. And I made it a color and then I added space and a dollar sign. And it gave me the code to cut and paste into my .bash profile. And it just works. I was really happy.
AVDI:
That sounds awesome.
JESSICA:
Yeah. It's a cute little site that somebody named Josh Matthews made. And I am grateful. Thank you, Josh Matthews.
AVDI:
David, how about you?
DAVID:
I just have one pick today. The Logitech H820e headset. I'm a huge fan of headsets. And I've picked long-range Bluetooth adapters in the past. And I was chatting with a coworker and I told him I would easily throw out a hundred dollars to have a long-range Bluetooth microphone on my headset. And he's like, “You need these 820s that I've got.” And he sent me a link to it on Amazon. And it wasn't a hundred bucks. It was like 130. So, be warned. These are a little bit pricey.
But it's a Bluetooth headset. Well, it's not Bluetooth. Sorry. It's a USB headset. It plugs into your laptop and then you dock the headset with it and it charges up the battery inside the headset. But when you pick it up and put it on your head, I'm actually podcasting with it right now. I'm using my better microphone. But when you got it on your head the link between the headset and the base station is, It's not Bluetooth. It's actually old school 900 megahertz cordless phone. And if anybody remembers having a cordless phone 15 years ago, they were designed by people who thought that it was reasonable to take your cordless phone to the neighbor's house four doors away.
AVDI: [Chuckles]
DAVID:
And so, I've literally been, I've been sitting here at my desk for this entire podcast but I could easily have not just gone to the bathroom because everybody thinks that that's why I want a cordless headset and they wouldn't be wrong. But the real advantage of this is that I can go check my mail halfway down the block. I can actually get all the way, I can almost get out of my subdivision and walk into Utah Lake from my front door and still have my headset working.
And so, if you're looking for a really good long-range headset, they're not good for music. I'll just throw that out there right now. They don't have a really wide range. They're really just perfectly notched for voice, just for speech communication. But if you don't mind switching to your really good cans when you want to rock your face off to some good music and then switching back to a little cordless headset when you want to do a podcast and what do you call it? The thing you do at work. Teleprompting, commuting, whatever these kids are doing these days, and being able to do a video call or a Skype call with somebody with these headset is absolutely a dream. So, that's my pick, the Logitech 820e headset. Absolutely love it.
AVDI:
Awesome. Erik, do you have any picks?
ERIK:
I do. So, last time I was on the show that was episode 127, I basically assumed that I would never be invited back so I picked 10 things. And I still stand by all those picks. So, if you want to go back and listen to that episode and the picks at the end in particular…
AVDI:
Did you just dereference a pick pointer?
ERIK:
I did.
DAVID:
[Laughs]
ERIK:
Following up on Jessica's pick I would also pick Fish as a shell, which if you use Bash and you want a custom prompt, that's cool. But Fish is quite a modern shell. And it takes a little bit of getting used to. But it has a really cool web interface so you can actually say fish config and it will start a web server and then you can open your browser and actually customize your prompt and things like that from a web interface on localhost down to picking individual colors for things, which is pretty cool, to have a modern shell that wasn't created in the 70s or 80s or whenever Bash was created. So yeah, that's another along the same lines of Crystal is a Ruby imagined for the 2010s, Fish is a modern shell as well, imagined for this decade.
And my only other pick will be the Rails Girls Summer of Code which is an amazing program. I've participated since the beginning for the past three years as a coach and mentor. They're fundraising now for their fourth year and you can make a donation at
RailsGirlsSummerOfCode.org/campaign. They've already raised about $50,000 from corporate sponsors. And I just put in a donation as an individual sponsor this morning right before this podcast. I think they haven't started the big marketing campaign to get individuals to donate. But they're trying to raise $100,000 total which will sponsor 20 women, 10 teams to basically spend the summer, three months learning how to code. And they get paid $5,000 each to do that so that they can quit their jobs or support themselves and just focus on learning to program.
And it's an incredibly successful program for the past few years. They've done it, there's an incredible success rate of women going through it and then becoming programmers out in the world, either getting jobs and doing it professionally or not, which I think is important as well. I think it's cool if people want to learn to program just as a hobby, because that's fine. That's awesome. But it does have an incredibly high success rate of teaching women to code and it's just a great program. So, I would say donate, sign up to mentor, sign up to coach if you want if you have some time to donate. And if you're a woman listening to the show who's new to programming and wants to become better at it, spend three months dedicated to it, it's an amazing way to do that.
DAVID:
That's awesome.
ERIK:
Yeah.
AVDI:
Sweet. Alright, well I have a few picks as well. The first thing I'll pick is RescueTime which is at RescueTime.com. I'd known about this for a long time and I'd always kind of ignored it because I always thought it was a service just for… I knew it was about time management. But I thought it was just for blocking yourself from time-wasting websites like setting up a port filtering rule to keep yourself from visiting Twitter or something like that during set periods of time. And that feature never really interested me that much.
But as I was trying to work on my schedule a bit and on my effective use of time, I took another look at it after some recommendations. And I realized that it also has pretty extensive just time tracking capabilities. And particularly time tracking where you don't actually have to take any action. It just sits there watching what you do, which is super creepy obviously as a software as a service kind of tool, but whatever. And I was also surprised to find that it was totally cross-platform. It works on OS X, Windows, and Linux, and Android and probably everything else. Yeah, so I've been using that for a while now. And while I will say that its user interface is a disaster, it's like a kitchen with two dozen cabinets where the kitchen implements have just been randomly distributed through the different cabinets.
DAVID:
[Chuckles]
AVDI:
And I keep finding new features because I had no idea that there was a feature in that cabinet or that there was even a cabinet there.
DAVID:
How much time have you spent hunting through them?
AVDI:
[Laughs] That, yeah. Amusingly to me it by default, it categorizes time spent on RescueTime.com as very productive.
DAVID:
[Laughs]
AVDI:
Which I find somewhat dubious. [Laughs] But it does collect an impressive amount of information. And if you can figure out where to find them, it gives you some good reports. And I've found it very helpful in giving myself incentives for using my time more effectively, because I'm really trying to regularize my schedule, get off at the same time every day, and spend quality time without guilt. So, it's been helpful for that.
I have a book pick. In my audio book listening I've been catching up on some of the classic, some of the clichéd personal improvement books. I think I picked 'How to Win Friends and Influence People' a while back. The last one I got through is 'The 7 Habits of Highly Effective People' by Stephen Covey. And while it is often, well in tone it is often just as smarmy as it sounds, honestly it's a really good book. There's a lot of really solid advice in there. And a lot of it's sort of more basic and fundamental and solid than advice I've seen in some of the more up-to-date how to be more effective as a person kind of books, because it really, really, really takes a principle and personal values perspective on things. It really starts from the fundamentals of 'Who are you as a person?' and builds on that. And rather than focusing on things like happiness or what you enjoy and stuff like that. So bottom line, yeah I think I'd recommend 'The 7 Habits of Highly Effective People'. I think there's some really good stuff in there. You just have to sort of grin and bear it in the chapter where he says synergy like every other sentence. [Laughs]
And finally, I have a beer pick. The beer pick is Whiplash White IPA from SweetWater Brewing Company. And I guess it's kind of a Belgian/IPA type beer. And I like it. It is good. That's my very technical beer review.
So, that's it for me. And I think that's it for our episode today. So, thank you very much everyone for coming.
DAVID:
This was awesome.
JESSICA:
Thank you, Avdi. Thank you, Erik. And thank you, David for popping in.
DAVID:
Thanks Erik. Yeah.
ERIK:
Yeah, thanks so much for having me and giving me a chance to spread the gospel about Crystal. It's a pretty exciting language and community and yeah, just hopefully the listeners will enjoy learning a bit more about it and maybe trying it out.
AVDI:
Ooh, thanks a lot.
[Hosting and bandwidth provided by the Blue Box Group. Check them out at BlueBox.net.]
[Bandwidth for this segment is provided by CacheFly, the world's fastest CDN. Deliver your content fast with CacheFly. Visit C-A-C-H-E-F-L-Y dot com to learn more.]
[Would you like to join a conversation with the Rogues and their guests? Want to support the show? We have a forum that allows you to join the conversation and support the show at the same time. You can sign up at RubyRogues.com/Parley.]