What would I change about Ruby?
Ruby is close to my favorite programming language. That does not mean I’m entirely happy with it. As an exercise, I’m writing up what I’d change about the language.
This is purely hypothetical — the thought of forking Ruby and making change is preposterous. But it is an interesting exercise!
Ruby was created in the mid-90’s. It’s now 25 years later, and there have been plenty of advances in programming languages, and the best practices around Ruby have emerged and mostly solidified. This creates a good opportunity to look back and reflect.
Symbols and (frozen) strings are too similar to warrant a distinction between the two.Clojure has symbols and (immutable) strings, and keywords on top of that. Keywords are similar to immutable strings, but can be namedspaced (e.g.
::foo is similar to
To do: Ooh, potentially plenty of implications of this.
Use one in-memory string encoding
Always encode strings as UTF-8. Provide a “data array” class to contain arbitrary data, and allow converting between strings and data, e.g.
Use distinct character literal
For strings, Ruby can use single quotes (e.g.
'example'), double quotes (e.g.
"example"), and percent-literal syntax (e.g.
%[example]). The ?-syntax can be used to construct single-character strings (e.g.
?x which is identical to
I believe character literals are useful, and other languages gravitate towards using single quotes for those.
first_name = "Denis" # This is a character literal, not a string first_name # => 'D' # This is a string, built from two character literals 'D' + 'e' # => "De"
Change keyword for defining functions and methods
A small one, but
def always strikes me as odd: you can’t use it for defining anything but functions and methods. Perhaps
class Person fun initialize(name) @name = name end end
Rename initializer method
Ruby’s constructor is called
class Person def initialize(name) @name = name end end
I find it difficult to type
initialize, and often make typos when typing it, which leads to hard-to-debug problems because the initializer does not exist.
Perhaps renaming it to
init could work. Or
Or, taking a page from Python’s book, using a clearly reserved name such as
__init__ is an identifier, not a keyword. What would that mean for other identifiers that are not keywords? Would we have
__self__ instead of
self? . This would allow the interpreter to detect typos: an unknown reserved name could be an error.
class Person def __init__(name) @name = name end end
Ruby already uses the double-underscore approach in some cases:
__callee__. Interestingly, these are implemented as methods on
Kernel — except
__FILE__, which is a constant, and that explains the rather unfortunate inconsistency in capitalisation.
Simplify assignment in initializer
Ruby’s initializer is verbose and repetitive when passing in many values:
class Person def initialize(first_name) @first_name = first_name end end
I rather like Crystal’s approach, providing a shorthand:
class Person def initialize(@first_name) end end
To do: It looks weird that the initialize method is now empty.
Treat modules are files
I’d like to have that more tightly integrated into the language. To do: OK, but… how would that work exactly?
To do: Then we can remove most of the indentation caused by nesting, which makes the code less rightward.
Make modules not globally available
To do: Ugh this is a big one
Simplify procs, blocks and lambdas
To do: Blocks are useful (distinct from functions) because they support non-local return.