The best kittens, technology, and video games blog in the world.

Wednesday, May 30, 2007

Why RLisp will not support Ruby class variables

Iris by SarahCartwright from flickr (CC-SA)
RLisp tries to be as Ruby-like as it reasonable can. For example it supports Global::Constants, @instance_variables, $global_variables, and self. It does not support semantically ugly features like Constants_Without_Fully_Specified_Scope, public/private/protected distinction, and Perlish magic variables of $~, $1 and family, trying to use cleaner solutions instead.

I'm adding another to the list of officially not supported features - @@class_variables. They simply lack any sensible semantics. The following code:

class Foo
@@xyzzy = 6
def hello
@@xyzzy
end
end

class Bar < Foo
@@xyzzy = 42
end

p Foo.new.hello
p Bar.new.hello
p Foo.new.instance_eval { @@xyzzy }

in Ruby 1.8 produces:
42
42
semantics_of_cvars.rb:16: uninitialized class variable @@xyzzy in Object (NameError)
from semantics_of_cvars.rb:16:in `instance_eval'
from semantics_of_cvars.rb:16

On the other hand in Ruby 1.9:
6
6
semantics_of_cvars.rb:16: warning: class variable access from toplevel singleton method
semantics_of_cvars.rb:16: uninitialized class variable @@xyzzy in Object (NameError)
from semantics_of_cvars.rb:16

I don't remember ever using class variables, but I had a vague feeling @@xyzzy would mean something like self.class.class_variable_get(:@@xyzzy). Apparently the meaning is much uglier and frankly I cannot see any situation in which it could possibly be useful in Ruby and even less so in RLisp - unlike Ruby def, RLisp fn/defun/method/... do not wipe out surrounding context, so we can use plain local variables.
(class Object
(let xyzzy 42)
(method hello () (print xyzzy))
; xyzzy is a normal lexical variable visible until we exit class definition
)
; not visible any more
[self hello] # => 42

3 comments:

Unknown said...

Out of curiosity, what lead you to name the operation "let"? The semantics of the operation seem closer to "define" (admittedly, define is picky about where it's used inside a nested scope, but it still seems closer than "let").

(define (foo x)
(define z 1)
(+ x z))

Obviously "let" is way shorter than "define" but it also might be unnecessarily confusing to lispers. What about "def", "var", "dec" or something?

I'd be interested to hear about your reasoning in a future post. Keep up the great blogging (and death to Ruby class vars)!

taw said...

topher: The "real" reason is that I coded in OCaml too much, and OCaml calls such operation "let".

When I stopped to think about it, I could find no other good name. "define" is too long, I don't like "var" because most of the time it's not going to be modified. "def" would be much more confusing to Rubyists than "let". I think "let" is the least bad choice.

James Britt said...

That's a really big eye.


And this is really great Ruby stuff!