[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: syntax sugar: treating an object like a method

Eric Mahurin

5/18/2005 7:39:00 PM

--- "David A. Black" <dblack@wobblini.net> wrote:
> Hi --
>
> On Thu, 19 May 2005, Eric Mahurin wrote:
>
> > I'm thinking of yet another RCR and would like to see if
> > anybody likes it. I think this would be a sweet feature.
> Here
> > are the basic components:
>
> I'm not sure what the canonical definition of syntactic sugar
> is, but
> I don't think that I think this is exactly that. Anyway....

In my book, syntactic sugar is when you have a more
concise/readable syntax that is equivalent to a more
fundamental (and longer) syntax. So by that definition, all of
the operators that equate to methods are syntactic sugar. I
think this thing I'm talking is similar to adding another
operator.

> > 1. Allow a null/default method to be defined in a class so
> that
> > the syntax "obj(*args,&block)" could be used. obj could be
> any
> > expression yielding a object. When you try to treat that
> > object as a method passing arguments and/or attaching a
> code
> > block to it, the null/default method would be called. I
> was
> > thinking "@" would be a good name for this method - like
> "+@"
> > and "-@". Here are a few example uses:
> >
> > * klass(*args) : you alias the null method to "new" so that
> > this would be equivalent ot klass.new(*args). I tend to
> forget
> > the ".new" more often than I'd like to admit.
>
> Forgetting .new is a weak reason for making it optional. It
> would be
> hard to argue that calling MyClass.new to create a new
> MyClass object
> is arcane or hard to get the hang of.

I know it is weak. But, it did seem to prod me to develop this
idea a little more - because the vast majority of time the only
thing you do with a class is call new.

> > * obj() : this could be aliased to clone in Object so that
> > default would be to just obj.clone
> >
> > * enum {...} : you could alias the null method to "each" so
> > that this would be equivalent to enum.each {...}
> >
> > 2. Allow an assignment method to be defined for an object
> ('='
> > is probably best). This would be called when you find an
> > object expression on the LHS whereas #1 is the equivalent
> for
> > the RHS. The ugly thing about this is that you have to
> make
> > sure that the object being assigned looks like an
> expression as
> > opposed to a variable or attribute assignment - surrounding
> is
> > parentheses makes it an expression that is normally illegal
> to
> > assign to. Along with '=', '+=', '-=', etc. becomes
> meaningful
> > in this context. You could also incorporate RCR 157/307 in
> > there allowing arguments. Here are a few example uses for
> > this:
> >
> > * (str) = value : this could default to "replace" for any
> > objects that respond to it (or if you use evil.rb -
> "become")
> >
> > * (mutable) += value : now the real += can be implemented
> for
>
> += is already the real +=. It's not the C or Perl +=, but
> it's the
> real Ruby +=.

Correct. "real" was the wrong word. How about "in-place"? A
normal += in Ruby creates a new object whereas this one
modifies an object in-place.

> > this since you are accessing the object rather than
> assigning
> > the variable. Of course Fixnum is immutable, so it doesn't
> do
> > you any good there. Other mutable classes (or ones that
> could
> > be made mutable - Float) could take advantage of this (for
> > example Array).
>
> To a large extent, my reaction to all of these examples comes
> down, as
> it often does, to the question: how would I explain this to
> someone to
> whom I was teaching Ruby (in person or in writing)? I think
> I would
> find it quite difficult to explain that in this:
>
> s = "hi"
> t = s
> (s) = "bye"

I think this is a good example to show the difference.
Programmers need to understand the difference shown above. One
assigns to a variable and one assigns into an object that a
variable has. Both are normal things you would want to do and
both are assignment-like.

> t is now "bye". I understand that there's really no such
> thing as
> "intuitive" computer language syntax, but this seems to be
> pushing it
> way in the other direction. I just can't see how wrapping
> something
> in parentheses can be hooked into any kind of explanation. I
> mean, it
> could be explained, just as ${var} = "hi" can be explained in
> Perl,
> but I really believe that very few things in Ruby, if any,
> travel this
> far from something reasonably self-evident to a reasonably
> large
> number of programmers.
>
> I also continue to be unconvinced of the need, usefulness, or
> desireability of any of the extra level of reference kind of
> thing.

Why do some of you think that everything I suggest has to do
with references? The initial reason I was wanting this was in
my BNF like classes thing (specify syntax in Ruby directly
rather than in some other language - yacc/lex). Right now I
have things like this:

int = (("0".."9")*(1..+1.0/0)).qualify { |m| m.to_s.to_i }

I use operator overloading quite a bit in this to create these
Syntax (renaming it to Grammar) objects. In the example above,
int now is used to match anywhere from 1 to an infinite number
of digits and the resulting parse tree (an array of digit
characters) is converted to an integer. In the above, it would
have been nice not to have to put the .qualify in there and
have it look like this:

int = (("0".."9")*(1..+1.0/0)) { |m| m.to_s.to_i }

That is where the idea originated. Nothing to do with
references.

> Similarly, obj() requires one to figure out whether or not
> there is a
> method called obj, and if there isn't to try to figure out
> what has
> been defined as () for this particular object.

Good point. It is similar to differentiating between a local
variable and a method call. Doing the above would do the same
between a method call and calling the default method in an
object:

xyz - could be a local variable (default) or a method call
xyz() - could be a method call (default) or a null method call
(xyz)() - definitely a null method call

> I fear that's the
> slippery slope to what people call "write-only code".

You could argue that. That is what Java designers said. And
that is why they didn't allow operator overloading. I think
operator is a good thing, but someone can easily abuse it and
make write-only code. I think what I'm suggesting here is like
adding more operators.




Yahoo! Mail
Stay connected, organized, and protected. Take the tour:
http://tour.mail.yahoo.com/mai...



5 Answers

Austin Ziegler

5/18/2005 9:04:00 PM

0

On 5/18/05, Eric Mahurin <eric_mahurin@yahoo.com> wrote:
> --- "David A. Black" <dblack@wobblini.net> wrote:
>> I'm not sure what the canonical definition of syntactic sugar is,
>> but I don't think that I think this is exactly that. Anyway....
> In my book, syntactic sugar is when you have a more
> concise/readable syntax that is equivalent to a more fundamental
> (and longer) syntax. So by that definition, all of the operators
> that equate to methods are syntactic sugar. I think this thing I'm
> talking is similar to adding another operator.

Yes. It's adding the #() operator, which is evil.

>> Forgetting .new is a weak reason for making it optional. It would
>> be hard to argue that calling MyClass.new to create a new MyClass
>> object is arcane or hard to get the hang of.
> I know it is weak. But, it did seem to prod me to develop this
> idea a little more - because the vast majority of time the only
> thing you do with a class is call new.

Very weak. And speak only for your own development. I use classes in
different ways for different projects.

>>> * (str) = value : this could default to "replace" for any
>>> objects that respond to it (or if you use evil.rb - "become") *
>>> (mutable) += value : now the real += can be implemented for
>> += is already the real +=. It's not the C or Perl +=, but it's
>> the real Ruby +=.
> Correct. "real" was the wrong word. How about "in-place"? A
> normal += in Ruby creates a new object whereas this one
> modifies an object in-place.

The case where you will need this is the very case that makes the ++
operator inappropriate and impossible in Ruby -- numeric values.

If you need to append to something in place, make a method that does
exactly that.

str = "foo"
str << "bar"

puts str # -> "foobar"

If you need a counter:

class Counter
def initialize(start = 0)
@counter = start
end

def inc
@counter += 1
end

attr_reader :counter
end

lines = Counter.new(0)
3.times { lines.inc }
puts lines.counter # -> 3

I'd much rather see the replacement concept explicitly specified as
making #replace a "standard" method that can (potentially) do a
bitwise copy of the object. This would also mean having #__replace__
in the same way that we have #__send__ and #__id__.

This is *clear*. Your proposal is not.

> Why do some of you think that everything I suggest has to do
> with references?

Because nearly everything you bring up has a reference-like mention
in it. This part is your own fault.

> The initial reason I was wanting this was in my BNF like classes
> thing (specify syntax in Ruby directly rather than in some other
> language - yacc/lex). Right now I have things like this:
>
> int = (("0".."9")*(1..+1.0/0)).qualify { |m| m.to_s.to_i }
>
> I use operator overloading quite a bit in this to create these
> Syntax (renaming it to Grammar) objects. In the example above,
> int now is used to match anywhere from 1 to an infinite number
> of digits and the resulting parse tree (an array of digit
> characters) is converted to an integer. In the above, it would
> have been nice not to have to put the .qualify in there and
> have it look like this:
>
> int = (("0".."9")*(1..+1.0/0)) { |m| m.to_s.to_i }
>
> That is where the idea originated. Nothing to do with
> references.

Sorry, but ick. I don't get where you even remotely think that not
having "qualify" is more intuitive or cleaner than having it. I'd
have to have some way of knowing and looking up that the "default
operator" is #qualify in this case. Talk about impossible to
maintain code.

>> I fear that's the slippery slope to what people call "write-only
>> code".
> You could argue that. That is what Java designers said. And that
> is why they didn't allow operator overloading. I think operator is
> a good thing, but someone can easily abuse it and make write-only
> code. I think what I'm suggesting here is like adding more
> operators.

Definable operators are a good thing. The () operator is not.
Therefore, this suggestion is not. (There are several operators that
are bad ideas in C++, which is why the Java designers prohibited
them. Specifically operator&, conversion operators, operator+=, and
a few others. This doesn't invalidate the whole idea, but it does
indicate that there are really dumb operators to overload.)

-austin
--
Austin Ziegler * halostatue@gmail.com
* Alternate: austin@halostatue.ca


Robert Klemme

5/18/2005 9:10:00 PM

0


"Eric Mahurin" <eric_mahurin@yahoo.com> schrieb im Newsbeitrag
news:20050518193919.90114.qmail@web41105.mail.yahoo.com...
> --- "David A. Black" <dblack@wobblini.net> wrote:
>> Hi --
>>
>> On Thu, 19 May 2005, Eric Mahurin wrote:
>>
>> > I'm thinking of yet another RCR and would like to see if
>> > anybody likes it. I think this would be a sweet feature.
>> Here
>> > are the basic components:
>>
>> I'm not sure what the canonical definition of syntactic sugar
>> is, but
>> I don't think that I think this is exactly that. Anyway....
>
> In my book, syntactic sugar is when you have a more
> concise/readable syntax that is equivalent to a more
> fundamental (and longer) syntax. So by that definition, all of
> the operators that equate to methods are syntactic sugar. I
> think this thing I'm talking is similar to adding another
> operator.

I would agree the "more concise" part if you mean "shorter" but I don't
follow you on the "more readable".

<snip/>

>> Forgetting .new is a weak reason for making it optional. It
>> would be
>> hard to argue that calling MyClass.new to create a new
>> MyClass object
>> is arcane or hard to get the hang of.
>
> I know it is weak. But, it did seem to prod me to develop this
> idea a little more - because the vast majority of time the only
> thing you do with a class is call new.

That might be true for you, but there's a lot of people around that do a lot
more with classes than just using them as POF (plain old factory).

>> += is already the real +=. It's not the C or Perl +=, but
>> it's the
>> real Ruby +=.
>
> Correct. "real" was the wrong word. How about "in-place"? A
> normal += in Ruby creates a new object whereas this one
> modifies an object in-place.

I like the clean way Ruby does this: you define +, -, * and / and you get
+=, +-, *= and /= automatically - and they all behave similarly.
Introducing in place modification would greatly complicate the matter - for
the ruby runtime as well as for readers of code.

Once I thought, it would have been better to do it the other way round: you
can define += and get + for free. But I have abandoned that thought because
it does not yield seamless type conversions, i.e. if you add something to a
big Fixnum you get a Bignum:

>> (1<<29).class
=> Fixnum
>> (1<<29+1).class
=> Bignum

Although C++ folks might argue that this sacrifices performance (and they
would be right) I prefer the cleaner approach of Ruby and wait for faster
hardware / Ruby runtimes; apart from that I either use a C extension or
another language if I am in desparate need for speed.

<snip/>

>> To a large extent, my reaction to all of these examples comes
>> down, as
>> it often does, to the question: how would I explain this to
>> someone to
>> whom I was teaching Ruby (in person or in writing)? I think
>> I would
>> find it quite difficult to explain that in this:
>>
>> s = "hi"
>> t = s
>> (s) = "bye"
>
> I think this is a good example to show the difference.
> Programmers need to understand the difference shown above. One
> assigns to a variable and one assigns into an object that a
> variable has. Both are normal things you would want to do and
> both are assignment-like.

"an object that a variable has"? Variables refer objects but they don't
exactly *have* them. I have to admit that I find the third line of the
example above very confusing. One of the reasons might be that there is a
quite similar construct - apparently with different semantics:

>> (a,b)=%w{a b}
=> ["a", "b"]
>> a
=> "a"
>> b
=> "b"

>> (a,)=%w{a b}
=> ["a", "b"]
>> a
=> "a"

<snip/>

>> Similarly, obj() requires one to figure out whether or not
>> there is a
>> method called obj, and if there isn't to try to figure out
>> what has
>> been defined as () for this particular object.
>
> Good point. It is similar to differentiating between a local
> variable and a method call. Doing the above would do the same
> between a method call and calling the default method in an
> object:
>
> xyz - could be a local variable (default) or a method call
> xyz() - could be a method call (default) or a null method call
> (xyz)() - definitely a null method call
>
>> I fear that's the
>> slippery slope to what people call "write-only code".
>
> You could argue that. That is what Java designers said. And
> that is why they didn't allow operator overloading. I think
> operator is a good thing, but someone can easily abuse it and
> make write-only code. I think what I'm suggesting here is like
> adding more operators.

IMHO Ruby has the right balance between no operator overloading at all
(Java) and too much operator overloading (C++).

Another note: as far as I remember there are plans to make () work for
lambdas. So currently we have

>> f = lambda {|x| x+x}
=> #<Proc:0x100c3e60@(irb):15>
>> f[10]
=> 20
>> f.call 10
=> 20

Then we had additionally

>> f(10)
=> 20

(Please correct me someone if I'm wrong here.) At the moment I don't fully
overlook the consequences and whether there were collisions but I have the
feeling that there might be - if not technical then at least in the area of
understanding and clearness.

That's my 0.02 EUR...

Kind regards

robert

Eric Mahurin

5/18/2005 9:51:00 PM

0

> >> To a large extent, my reaction to all of these examples
> comes
> >> down, as
> >> it often does, to the question: how would I explain this
> to
> >> someone to
> >> whom I was teaching Ruby (in person or in writing)? I
> think
> >> I would
> >> find it quite difficult to explain that in this:
> >>
> >> s = "hi"
> >> t = s
> >> (s) = "bye"
> >
> > I think this is a good example to show the difference.
> > Programmers need to understand the difference shown above.
> One
> > assigns to a variable and one assigns into an object that a
> > variable has. Both are normal things you would want to do
> and
> > both are assignment-like.
>
> "an object that a variable has"? Variables refer objects but
> they don't
> exactly *have* them.

Bad wording - sorry.

> I have to admit that I find the third
> line of the
> example above very confusing. One of the reasons might be
> that there is a
> quite similar construct - apparently with different
> semantics:
>
> >> (a,b)=%w{a b}
> => ["a", "b"]
> >> a
> => "a"
> >> b
> => "b"
>
> >> (a,)=%w{a b}
> => ["a", "b"]
> >> a
> => "a"

And with what I proposed add to that list (assuming the
()/default/null method is replace):

>> (a) = %w{a b} # a.replace(%w{a b})
TypeError: cannot convert Array into String
>> (a),(b) = %w{a b} # a.replace("a"); b.replace("b")
> => ["a", "b"]
> >> a
> => "a"

This doesn't collide with any syntax, but I could see confusion
especially in light of the existing multi-assignments.

> IMHO Ruby has the right balance between no operator
> overloading at all
> (Java) and too much operator overloading (C++).

Obviously I would like a little more, but Ruby is the closest
to my tastes also.

> Another note: as far as I remember there are plans to make ()
> work for
> lambdas. So currently we have
>
> >> f = lambda {|x| x+x}
> => #<Proc:0x100c3e60@(irb):15>
> >> f[10]
> => 20
> >> f.call 10
> => 20
>
> Then we had additionally
>
> >> f(10)
> => 20

Cool. So, this sounds like the ()/null operator is being
implemented with procs/lambdas. Now if we could just have it
for the rest of the objects.




__________________________________
Yahoo! Mail Mobile
Take Yahoo! Mail with you! Check email on your mobile phone.
http://mobile.yahoo.com/...


dblack

5/18/2005 11:22:00 PM

0

Robert Klemme

5/19/2005 8:20:00 AM

0

Eric Mahurin wrote:
>>>> To a large extent, my reaction to all of these examples comes
>>>> down, as
>>>> it often does, to the question: how would I explain this to
>>>> someone to
>>>> whom I was teaching Ruby (in person or in writing)? I think
>>>> I would
>>>> find it quite difficult to explain that in this:
>>>>
>>>> s = "hi"
>>>> t = s
>>>> (s) = "bye"
>>>
>>> I think this is a good example to show the difference.
>>> Programmers need to understand the difference shown above. One
>>> assigns to a variable and one assigns into an object that a
>>> variable has. Both are normal things you would want to do and
>>> both are assignment-like.
>>
>> "an object that a variable has"? Variables refer objects but
>> they don't
>> exactly *have* them.
>
> Bad wording - sorry.
>
>> I have to admit that I find the third
>> line of the
>> example above very confusing. One of the reasons might be
>> that there is a
>> quite similar construct - apparently with different
>> semantics:
>>
>>>> (a,b)=%w{a b}
>> => ["a", "b"]
>>>> a
>> => "a"
>>>> b
>> => "b"
>>
>>>> (a,)=%w{a b}
>> => ["a", "b"]
>>>> a
>> => "a"
>
> And with what I proposed add to that list (assuming the
> ()/default/null method is replace):
>
>>> (a) = %w{a b} # a.replace(%w{a b})
> TypeError: cannot convert Array into String
>>> (a),(b) = %w{a b} # a.replace("a"); b.replace("b")
>> => ["a", "b"]
>>>> a
>> => "a"
>
> This doesn't collide with any syntax, but I could see confusion
> especially in light of the existing multi-assignments.

And it looks totally ridiculous to me. Why is the instance where you send
the method to *inside* brackets and not *before* them? That's probably as
unobvious as it can get.

>> IMHO Ruby has the right balance between no operator
>> overloading at all
>> (Java) and too much operator overloading (C++).
>
> Obviously I would like a little more, but Ruby is the closest
> to my tastes also.
>
>> Another note: as far as I remember there are plans to make ()
>> work for
>> lambdas. So currently we have
>>
>>>> f = lambda {|x| x+x}
>> => #<Proc:0x100c3e60@(irb):15>
>>>> f[10]
>> => 20
>>>> f.call 10
>> => 20
>>
>> Then we had additionally
>>
>>>> f(10)
>> => 20
>
> Cool. So, this sounds like the ()/null operator is being
> implemented with procs/lambdas. Now if we could just have it
> for the rest of the objects.

It'll probably work as general mapping to #call so it would work with
everything that has #call.

Cheers

robert