The Crystal Programming Language Forum

Iterating the language reference (aka: crystal-lang/crystal-book)

There are a couple of changes related to documentation we would like to arrive in mid-term.

I would like to discuss the general scope of the crystal-lang/crystal-book and the general aspect of the changes.

  1. It should be a reference for the language
  2. It should be a reference for the built-in tooling
  3. It should have introductions for using Crystal in a couple of scenarios and point in directions to keep digging deep
  4. It should some sections for different aspects (ie: concurrency, performance, database, etc)
  5. It should have guides for usual best practices for the ecosystem (ie: publishing shards, docs, CI)

The last item will probably evolve faster than the others but is content I would prefer to have an official reference for rather than posts in different places. Definitely those posts can be used to keep the content up to date to things changing outside crystal.

The main thing that is currently in the book that I would like to see them changed:

  1. Installation methods. I believe is better to put that content on the website itself. I don’t want a book that tells me the installation method for 15 distros and their caveats.
  2. The initial opening is the readme of the repo instead of an introduction of what the content is. (Note: the learn link in the website jumbo banner should point to this intro I guess)
  3. The table of content should be adapted for better navigation of the above goals.

And last, usually, books have some full sample code the reader can checkout and use. Not for all snippets, but for some chapters/sections it would make sense. These samples could be stored in the same repo to keep them in sync easier I guess.

What other general aspects will be good to have in mind to achieve a better learning and reference resource?

5 Likes

I have written tens of thousands of lines of code using Crystal. Created several mature applications.
In the meantime, I have encountered many compiler bugs. Some of them have already been recorded, and some are my own feedback.

I think it is necessary to emphasize that Crystal is not very perfect at present. If you encounter problems, you should immediately ask the community for help. Otherwise the learner may take a long time to find the problem or eventually give up.

PS: Bringing learners here can also make this forum even more lively.

1 Like

I think we should move the Crystal wiki to its own repo, to better to contribute to it.
OS specific stuff could be moved to it too.

Another point is GitBook, which no longer has open source releases. mdBook is a good alternative.

How is your experience with this? Was Crystal good enough despite those bugs?

I am already very satisfied with it. I use a lot of languages, Crystal definitely has disadvantages compared to other languages, but I understand that different languages have different styles, and it is impossible to ask a language to combine the advantages of various languages.
I mainly want to express: It is very important to guide learners to come here to communicate. Many things do not understand, or they may be bugs.

Adding “the way to get help” to the crystal-book may have some meaning. For example, come to this forum to communicate.

4 Likes

Oooooh! This is something I’m very interested to contribute to. In particular I’d be glad to give what feedback I can as a fairly green coder getting into Crystal. TBH, it’s the first time I’ve ever felt like I had access to the low level, save for Microcontrollers. I’ve found C, C++, Java, etc to be quite daunting, but the Ruby syntax made a lot of things here quick to grasp.

I’ve been language jumping A LOT the last two weeks and I’ve actually been rating them in my head by what I’m calling “mouthfeel”; that first impression as you take a bite, before you even taste the flavor. My basic criteria is how quickly one can have a complete “Hello World” from the time they’ve decided to try it out. Crystal is on the VERY HIGH end of the spectrum, I built my “Hello World” to a binary about 5 mins after discovering the language. The only other languages I can boast that with have been ones that are in the long-time GNU collection of languages, even Ruby can be a bit of hassle to get started your first time ever.

That said I agree with all of the points you are making, the next step after the first plunge can be pretty tricky. There aren’t a lot of examples related to the domains I’m working in, I still honestly don’t understand spawn and fibers and all that. And many on gitter can attest to how many fundamental questions I’m asking that could be summed up in a few practical examples. :smiley:

The other language that’s caught my attention for helping me grasp it all pretty quickly is kotlin, oddly. Even though I’ve had to fight my way through understanding what parts of the jvm I need, the actual startup experience is really thorough and helpful. They do a 4 section playground with a play, tutorial projects, example, and “koan” section. If any language needs koans like Ruby, it’s us. Plus it’s a great way to show off how epic the crystal play interpreter is, I’d consider it the key to making minimal examples matter less when you can pick apart every step of the data.

And yes, I agree that we need to work on the linux install instructions a bit. I did an Alpine install yesterday, and being my first one I had to do a lot of head scratching before I got my hello world out, I needed to install a package called musl for it to work. But get it all on one page, list out the various distro methods, possible dependencies that might be out of date, all that. I’d be glad to run through the experience on vanilla builds of every main distro including the BSDs while I’m playing with QEMU a lot.

Please let me know how to contribute directly, helping with docs will help me be as proficient as I’d like to be.

One thing I’d like to see is a dedicated section on the most common “gotchas”. In particular, for those coming from other languages.

For example, every Ruby programmer I’ve taught Crystal to runs into this at some point and just doesn’t understand until the why and the how to fix is taught to them. Once they’ve learned it, it’s simple, but it’s a very common “gotcha”. However, it’s very hard to search for something like this if you’re on your own, and a dedicated section would help them.

class Foo
  getter number : Int32?

  def do
    if number
      puts number + 1
    end
  end
end

# 
# in blah.cr:6: undefined method '+' for Nil (compile-time type is (Int32 | Nil))
#
#       puts number + 1
#
2 Likes

100% agree on that! And on top of that I think including in the error message that a little description of suggestions on common fixes would be great. “Assign the value to a local variable to use a method or instance variable as a conditional” along with a short example. That would really help I think

There could also be simple things (that ppl unfortunately doesn’t always do) like “how to read a compiler error”, “I found something weird (could be a bug or a crystal feature) where do I go to to understand/fix it?”

I started using Crystal a year ago (Golang and Ruby coder) and was able to rewrite my compiler from Golang to Crystal in a couple of months. In the process I found some bugs in my Golang compiler code which I otherwise would not have found. Coding in Crystal is fun and I try to convince others to learn and use Crystal.

Back to your example, I ran into that same problem and looked at the error message and did not know how to fix it. Not sure the following is correct ?

class Foo
  getter number : Int32?

  def do
    if number
      temp = number.not_nil!
      puts temp + 1
    end
  end
end

That’s fine but it’s not the ideal way of doing it. The problem with that approach is that you know that number can’t be nil inside the if but the not_nil! call will check that again.

The best way to do that would be:

local_number = number
if local_number
  puts local_number + 1
end

Or inline in the if:

if local_number = number
  puts local_number + 1
end

Above I said:

The problem with that approach is that you know that number can’t be nil inside the if but the not_nil! call will check that again

But that’s not entirely true. If Foo is in a mutlithreaded environment and @number is mutable (which is not in this case, but let’s suppose that) then there’s a chance that between checking if number and calling number.not_nil! that @number became nil. Then you’ll get a runtime error.

That’s why using a local variable is better: there’s no chance that the check you do in one place won’t hold later on. And the compiler knows that and that’s why not_nil! is not needed anymore.