From: Markus Date: 2004-10-09T12:12:23+09:00 Subject: Re: ANN: Free-form-operators patch On Fri, 2004-10-08 at 15:39, Jim Weirich wrote: > Charles Hixson said: > > This is one place that I don't think Eiffel got things quite right. > > Precedence should be defineable, not necessarily higher than all > > built-in operators. If one is defining a cross-product, e.g., one > > doesn't necessarily want it to be of higher precedence than whatever one > > is using to define the literal representation of the matrix. And > > ordinary arithmetic might be of even higher precedence. E.G.: > > > > | .< 1 + 3, 5 * 2, 6 / 3 >. .. .. | .*. M > > Hmmmm ... I'm not sure that the .<, >. and | are technically operators > (certainly not binary operators). They seem to be merely syntactical > markers. You could do it, but it would be kludgey unless you generalized it properly (i.e. take the people who designed smalltalk and the people behind postscript out for a beer and take notes). The basic trick: define a class that is a "partial structure" and is the result (and consumer) of the individual expressions. But without doing gymnastics, you're right. > The problem with definable precedence is that precedence is a compile time > operation and the selection of the operator implementation is a run time > thing. Consider ... > > x @a y @b z > > (note: Syntax is Eiffel style syntax, so @a and @b are operators. Ignore > for the moment that this conflicts with Ruby syntax for instance variables > and go with me here). > > Should this be parsed ((x @a y) @b z) or (x @a (y @b z))? Operators are > generally transformed into method calls, e.g. (x @a y) => (x.@a(y)). So > we look at the runtime class of x to find the operator and determine the > precedence. Unfortunately, at the time the expression is compiled the > runtime class of x isn't available! Indeed, x may have a different class > every time the expression is executed. > > So, that leaves us two choices: (1) Reparse the expression everytime it is > executed, or (2) globally define the precedence of an operator across all > classes. > > (1) seems a bit too dynamic for my taste, and (2) is troublesome when you > have more than one class defining the operator. This is a very good description of why I'm unsure about letting the user set the precedence/associativity/arity. Do you mind if I use it? The best answer I have come up with so far, is to require that if they're compile-time properties are changed they must be declared before their first use, and that any additional declaration must match. Declarations of this sort are not commonly done in ruby (but they are not unheard of either). > Given that, I wouldn't mind user defined operators in Ruby under the > following conditions... > > (A) The operators are visually distinctive. In Eiffel, all user defined > operators must begin with a limited set of symbols (@, #, &, and | IIRC). > After the initial symbol, any printable, non-space character is allowed. > So @in, @cross, &and, #..# are all recognized as operators according to > the Eiffel rules. I'm being a bit more conservative at this point: only characters that are already found in ruby operators (and only on combinations that are not already used) may be user defined. > (B) Fixed precedence. User defined unary operators should have the same > precedence as other unary operators. User defined Binary operators should > be the same as the highest precedence binary operator under the unary > operators. Why the highest? I know that's how eiffel does it, but I don't recall the rational. I've also considered some function of the length or contents (such that the built in operators would "fit" the scheme), but I haven't found anything I like. > Point A means that I don't have to parse a random string of symbols in my > head and decide whether it is legal Ruby syntax or user defined operators > (or Beetle Baily swearing). Ruby's problem is that all the punctuation > characters are already used for other purposes, it would be difficult to > set aside yet another character for this purpose. Perhaps something like > @op@ can be used. I think "duck typing" on character classes does the job nicely. If it looks like an operator (e.g., like => <-+ +/- !~~, etc. it is composed of (and only of) the characters used in ruby to construct operators and noting else) it is an operator. > Regarding the matrix example, I find it less than compiling, especially > when existing Ruby can be used to get something quite readable ... > > Matrix [ > [ 1 + 3, 5 * 2, 6 / 3 ], > [ n21, n22, n23 ], > [ n31, n32, n33 ] > ].cross M I agree, though I think the initial point was about the value of being able to experiment to find a comfortable notation, and not so much that the example provided was the best one. -- Markus