From: Daniel Brockman Date: 2005-07-19T08:14:30+09:00 Subject: Re: `not' in parameter lists This message ended up getting pretty long and off-topic, with lots of jabbering about syntax, and ending with a shameless plug. So read it at your own risk. twifkak@comcast.net writes: > On Jul 17, 2005, at 2:34 PM, Daniel Brockman wrote: > >> Consider these two examples: >> >> assert not foo.bar? >> >> assert not foo.bar? and not baz.quux? >> >> I don't think it would be acceptable to have the former work >> as intended, while the latter would siletly misbehave. > > I disagree. The order of precedence of the operators is > advertised, and plenty of things fail silenty. (see duck typing) After some consideration, I've changed my mind. This is alledgedly confusing: assert not foo.bar? and not baz.quux? But this is already allowed, and just as confusing: assert foo.bar? and not baz.quux? As you imply, anyone who is familiar with the order of precedence of the boolean operators will type this: assert not foo.bar? && not baz.quux? They will not expect this to mean the same: assert not foo.bar? and not baz.quux? So I'm back on track again believing that ‘not’ *should* be allowed in parameter lists after all. >>> While I think a lisp-like syntax is immensely powerful >>> from a programatic standpoint I think that it can be >>> difficult for a human to read and understand quickly. >> >> I would have to agree. > > assert ((foo.respond_to? :bar) and (plurgh.include? :mif)) > > Difficult to read and understand? Not particularly, but a little. I'm not used to that style, which I guess is why I actually consider the full-blown Lisp syntax more readable: (assert (and (foo.respond_to? :bar) (plurgh.include? :mif))) Of course, the conventional Ruby style is just as readable: assert foo.respond_to?(:bar) && plurgh.include?(:mif) The real readability benefits of a Ruby-like syntax over a Lisp-like one I think comes from the fact that where Ruby has keywords, Lisp leaves it to positionality and list structure to define the meaning of parts of an expression. Compare this (I'm sorry I couldn't be bothered to come up with a less brain-dead example) case when bar.respond-to? :moomin puts "snufkin" else something-or-other end to this: (cond ((respond-to? bar :moomin) (puts "snufkin") (t (something-or-other)) I think the former (Ruby) is much more readable. But now consider this Lisp/Ruby hybrid: (case (when (bar.respond-to? :moomin) (puts "snufkin") (else (something-or-other)) Pretty nice, ain't it? I think it's better than its parts. Alas, the current Ruby parser only lets you go this far towards Lisp, (case when (bar.respond-to? :moomin) (puts "snufkin") else (something-or-other) end) which I think is insufficient, leaving you with a weird Ruby-with-too-many-parens syntax. >> The problem, ultimately, is that you can't meaningfully do: >> >> foo bar baz, moomin snufkin I think you mean ‘unambiguously’, not ‘meaningfully’. Of course you can assign meaning to the above code. Anyway, you *can* unambiguously do this: foo bar(baz), moomin snufkin Therefore, I think the parentheses of a last-parameter nested method call should be optional, analogously to the implicit hash syntax. What I'm saying is that this foo bar(baz), moomin => snufkin already means this, foo bar(baz), { moomin => snufkin } so why not make this foo bar(baz), moomin snufkin mean this? foo bar(baz), (moomin snufkin) That'd allow the common use case of ‘foo bar baz’: assert foo.respond_to? :bar > Indeed. I have been schooled, yet again. OK, well I'm > still hoping for LISP-with-commas. :) We already have Lisp with commas, infix operators, some miscellaneous nice syntactic constructs, no ‘QUOTE’, optional parentheses (based on lines), mandatory ‘end’s, arrays instead of lists, and a limited answer to macros. Well, pretty much. If we could just leave out the ‘end’s, we'd be pretty close[1] to getting the best out of Lisp's syntax (except we still wouldn't have ‘QUOTE’). Maybe you'd be interested in a preprocessor[2] that lets you use hyphens instead of underscores? It throws in a few additional things like allowing this @timers.each { .fire if .ready? } as a shortcut for this, @timers.each { |t| t.fire if t.ready? } and this Transfer.new ~:file-name, ~:file-size, ~:file-offset as a shortcut for this: Transfer.new \ :file-name => file-name, :file-size => file-size, :file-offset => file-offset It also adds ‘<-’ as a synonym for ‘=’, which lets you write things like this, if connection <- @socket.accept signal :new-connection, connection end instead of the equivalent with an equals sign (which in this case can't really be confused with ‘==’, thanks to context), if connection = @socket.accept signal :new-connection, connection end (I'm still not sure whether I like this last one.) Of course, it would be nicer if the good ones of these features were integrated into the language, but most probably won't, and even if some might, that'll take time. That's not going to stop me from using them, though. :-) The preprocessor is automatic, and doesn't get in my way. -- Daniel Brockman [1] [2] So really, we all have to ask ourselves: Am I waiting for RMS to do this? --TTN.