Ruby opinions (111)

1 Name: #!usr/bin/anon 2005-11-23 17:55 ID:rgxG1g8s

I am learning Ruby right now, to play with Ruby on Rails, and I don't know yet wether I like it or loathe it, it looks pretty much like the illegitimate child of Perl and Python, which sounds very wrong.

What are your opinions about Ruby?

101 Name: dmpk2k!hinhT6kz2E : 2007-11-07 06:24 ID:Heaven

No need to tell me. 18 months of Zope3 has left me with deep loathing for anything related to it. I'm still having trouble going near Python because of memories of Zope.

102 Name: #!/usr/bin/anonymous : 2007-11-07 16:46 ID:Heaven

http://mail.python.org/pipermail/python-dev/2003-May/035727.html

You're doing it wrong. Eliminate your startup by only doing it once- dump core, and unexec the result.

103 Name: #!/usr/bin/anonymous : 2007-11-10 01:08 ID:6kOzKjm7

I think you guys are all forgetting Ruby's fun factor here.

104 Name: #!/usr/bin/anonymous : 2007-11-10 10:16 ID:Heaven

>>102 has a good point, this was a common trick back when people were complaining about Perl being slow.

Of course I don't know about it being very cross-platform.

105 Name: dmpk2k!hinhT6kz2E : 2007-11-10 21:11 ID:Heaven

Let's talk Ruby's blocks, since they're a feature that is routinely brought up as a point in Ruby's favour. Since the rest of Ruby has broken lexical scoping and no first-class functionsmethods -- a rant for another day if someone asks -- blocks are Ruby's claim to fame.

Ruby borrowed the idea of blocks from Smalltalk. That was probably a good idea. Unfortunately, like almost everything else in Ruby, they're half baked.

First up, lexical scoping. Blocks come pretty close to behaving as they should here. Just one problem:

y = 0                     
[ 'o shi' ].map { |y| puts y } => 'o shi'
puts y => 'o shi' (should be 0)

Given that the argument to the block, y, is in a different scope to the y outside, you'd expect that after this chunk of code is executed, y would still be 0. No, it's 'o shi'. So arguments to a block stomp all over variables in outer scopes.

The next (much smaller) problem is that blocks are not first-class objects:

x = { |y| }
SyntaxError: compile error
(irb):1: syntax error, unexpected '|', expecting '}'
x = { |y| }
^
from (irb):1

Nope.

In Smalltalk they were first-class objects, but in Ruby procs are. One consequence is that there's no way to pass multiple blocks to a method short of converting them to procs first. Why the nuance? Who knows!

(I suspect it's partly because Ruby's grammar is foobar and uses {} for both blocks and hashes. The more worrisome part is that the performance characteristics are substantially different, which possibly hints at different means of implementation.)

See >>50 for another reason why I am not in favour of this in Ruby. If you want an example of a language that has the whole lexical scoping and first-class everything right, see Lua.

106 Name: dmpk2k!hinhT6kz2E : 2007-11-18 03:31 ID:Heaven

Another annoyance. This is a constant:

VAR = 0

Constants shouldn't change, right?

VAR += 1
(irb):2: warning: already initialized constant VAR

...okay, so you can change it, but there's a warning. Livable, I suppose. But what if it's not a scalar?

VAR = []
VAR.push 1 => VAR now equals [1]

Alas, this little stupidity means I can't do things like the following, since they're all now pointing to -- and can mutate -- the same object:

DEFAULT = [ 0, 0, 0, 0 ]
var1 = DEFAULT
var2 = DEFAULT
var1[0] = 1 => var2 is now -also- equal to [ 1, 0, 0, 0 ]

There are a few alternatives, two being: use .freeze() on the array when assigning to DEFAULT, or use .dup() when assigning to var1 or var2. The problem with freezing the array is that I can no longer mutate var1 or var2 since they're pointing to DEFAULT's frozen array; this defeats the purpose of creating DEFAULT. dup() has its own problems, for example:

DEFAULT = [ [0, 0, 0], [0, 0, 0] ]
var1 = DEFAULT.dup
var1[0][0] = 1

Guess what that does?

There are a number of ways around this. The one I've settled on for now is to create a method named DEFAULT() that returns a new copy of what I want. E.g.:

def DEFAULT
[ 0, 0, 0, 0 ]
end
var1 = DEFAULT()

Nevertheless, Ruby's constants aren't really constant for anything beyond a scalar.

This and a couple other experiences have finally given me an opinion on implicit pass-by-reference semantics: they're a pain. Perl and C have the right idea: the semantics are pass-by-value; if you want a reference or pointer, you know how to get it.

(NB: those of you who want to argue about passing large structures with pass-by-value semantics please see what OS's have been doing for decades: copy on write.)

107 Name: #!/usr/bin/anonymous : 2007-11-24 13:56 ID:c3WTWrjl

Yep, this is an issue with other languages too. Java, for instance, has no real notion of a constant either. Instead, you have statics, and as long as you put immutable objects in there then you're okay. Same workaround in Ruby, put an immutable object there instead of an array.

108 Name: #!/usr/bin/anonymous : 2007-12-01 05:01 ID:Heaven

>>107 Neither did Fortran:

       CALL FUN(41)
WRITE (10,1) 5
1 FORMAT (I5)
END
       SUBROUTINE FUN (I)
I = I + 1
END

109 Name: #!/usr/bin/anonymous : 2007-12-03 00:26 ID:7xvAlNy9

110

111 Name: #!/usr/bin/anonymous : 2008-01-05 02:25 ID:66OZq0xr

>>105

>So arguments to a block stomp all over variables in outer scopes.

Believe that's been fixed in 1.9.

Name: Link:
Leave these fields empty (spam trap):
More options...
Verification: