Creating bang methods

J

Jon Hurst

(newbie) I can't for my life figure out how to create bang methods. Please
help.
~Jon Hurst
 
A

Ara.T.Howard

(newbie) I can't for my life figure out how to create bang methods. Please
help.
~Jon Hurst


class Foo
def bang_method!
# probably something that modifies a Foo in place
end
end

-a

--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
| URL :: http://www.ngdc.noaa.gov/stp/
| TRY :: for l in ruby perl;do $l -e "print \"\x3a\x2d\x29\x0a\"";done
===============================================================================
 
J

Jon Hurst

On reflection, perhaps I have not been clear enough. I would like to create
bang methods of some math functions (mostly abs), but I don't know how to
modify the reciever in place because the value of self cannot be changed.
It's not really important that I be able to write these bang methods, but I
would very much like to understand how one would do it.

Class Numeric
def abs!
??
end
end

~Jon Hurst
 
G

Gavin Kistner

[...] I would like to create bang methods of some math functions
(mostly abs), but I don't know how to modify the reciever in place
because the value of self cannot be changed.

This problem bit me repeatedly. It's sort of a design feature, not a
flaw, as I understand it.

Certain base classes are not meant to be mutable, per the design of the
language. The 'best' way to do this, I've been told, is what I did for
my MutableTime class, to wit:
a) Create a new class (that doesn't inherit from the other)
b) Keep your own instance variable that is the base class
c) When you need to modify the instance, swap out your instance,
otherwise
d) Pass method calls on to the instance.

For example, something like

class MyNumber
def initialize( initialValue=nil )
@n = initialValue || 0
end

def abs!
@n = @n.abs
end

def method_missing(meth, *args, &block) # :nodoc:
@n.send(meth, *args, &block)
end
end


There are various drawbacks to this, but...there you go. There's *an*
answer, anyhow.
 
J

Jean-Hugues ROBERT

On reflection, perhaps I have not been clear enough. I would like to create
bang methods of some math functions (mostly abs), but I don't know how to
modify the reciever in place because the value of self cannot be changed.
It's not really important that I be able to write these bang methods, but I
would very much like to understand how one would do it.

Class Numeric
def abs!
??
end
end

~Jon Hurst

Some objects provide a .replace(): strings, hashes...
I don't know about numerics but they look like immutable to me,
so you may need a Facade delegating most of the work to the
immutable object. I think there is a delegator.rb that may help,
if delegate can be changed on the fly (I haven't checked)

Jean-Hugues
 
S

Stephan Kämper

Jon said:
On reflection, perhaps I have not been clear enough. I would like to create
bang methods of some math functions (mostly abs), but I don't know how to
modify the reciever in place because the value of self cannot be changed.
It's not really important that I be able to write these bang methods, but I
would very much like to understand how one would do it.

Class Numeric
def abs!
??
end
end

Even if you had a way to implement some bang-abs, what would you expect
-4.abs! to be?


Happy rubying

Stephan
 
D

David Alan Black

Hi --

Jon Hurst said:
On reflection, perhaps I have not been clear enough. I would like to create
bang methods of some math functions (mostly abs), but I don't know how to
modify the reciever in place because the value of self cannot be changed.
It's not really important that I be able to write these bang methods, but I
would very much like to understand how one would do it.

Class Numeric
def abs!
??
end
end

Not being able to assign to self actually isn't the issue (no method
can do that). I think you want this:

x = -1
x.abs!

to result in x == 1, but that isn't how bang methods work; i.e., they
don't assign a new object to a variable, but rather they change an
object in place (and, if there are one or more variables referencing
that object, those variables don't "know" that this has happened).

irb(main):002:0> x = [1,2]
=> [1, 2]
irb(main):003:0> x.id
=> 537881530
irb(main):004:0> x.reverse!
=> [2, 1]
irb(main):005:0> x.id
=> 537881530

Nothing has happened to x in this example (no reassignment) but the
underlying array has been modified.

The problem with abs! is that you can't modify a number in place,
because numbers are immediate values (even when referenced by
variables), and there's only one copy of each in existence. So if you
did this:

-1.abs!

then henceforth 1 + -1 would be 2, because you would have changed -1
*itself* to 1 (not just assigned 1 to a variable that previously
referenced -1). The same would be true of this:

x = -1
x.abs! # x is the immediate value -1

This is also why there are no ++ and -- operators in Ruby. 1++ would
mean that the actual number 1 would henceforth mean 2.


David
 
A

Ara.T.Howard

This is also why there are no ++ and -- operators in Ruby. 1++ would mean
that the actual number 1 would henceforth mean 2.

i think we should try to talk matz into this for a minor release. maybe the
release slated for 2005-04-01?

-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
| URL :: http://www.ngdc.noaa.gov/stp/
| TRY :: for l in ruby perl;do $l -e "print \"\x3a\x2d\x29\x0a\"";done
===============================================================================
 
D

David Alan Black

Hi --

Ara.T.Howard said:
i think we should try to talk matz into this for a minor release. maybe the
release slated for 2005-04-01?

:) And we could speed it up:

2005--
22.times { 1++ }

Hmmm.... I see the makings of a Hollywood sci-fi blockbuster....


David
 
R

Robert Klemme

Gavin Kistner said:
[...] I would like to create bang methods of some math functions
(mostly abs), but I don't know how to modify the reciever in place
because the value of self cannot be changed.

This problem bit me repeatedly. It's sort of a design feature, not a
flaw, as I understand it.

Certain base classes are not meant to be mutable, per the design of the
language. The 'best' way to do this, I've been told, is what I did for
my MutableTime class, to wit:
a) Create a new class (that doesn't inherit from the other)
b) Keep your own instance variable that is the base class
c) When you need to modify the instance, swap out your instance,
otherwise
d) Pass method calls on to the instance.

For example, something like

class MyNumber
def initialize( initialValue=nil )
@n = initialValue || 0
end

One check too much.
def abs!
@n = @n.abs
end

def method_missing(meth, *args, &block) # :nodoc:
@n.send(meth, *args, &block)
end

Those two can be combined.

How about:

class MyNumber
def initialize( initialValue = 0 )
@n = initialValue
end

def method_missing(meth, *args, &block)
if /\!$/ =~ meth.to_s
@n = @n.send(meth.to_s[0...-1], *args, &block)
else
self.class.new @n.send(meth, *args, &block)
end
end

# eql, == etc still missing here
end

x = MyNumber.new -10
p x
x.abs!
p x

Regards

robert
 
D

David Alan Black

Hi --

Jean-Hugues ROBERT said:
Well... something++ could get expanded into (something = something.++()) ?
And ++something get expanded into (tmp = something, something =
something.++(), tmp)
Pure syntax sugar.
Then you can:
def ++()
self + 1
end
I think += does that already, doesn't it ?
There are other reasons why there is no ++ in Ruby.

Well, I'll take your word for it, but apparently Matz is keeping them
secret :) I'm just summarizing the reasons Matz has talked about in
the past (the illogic of incrementing integers, which are unique and
immutable, and which are present as immediate values in the variables
that represent them).

Of course the parser could be taught to do what you describe -- it's
just that it wouldn't make sense. Keep in mind that these two things
are equivalent:

1++

and

x = 1
x++

so if the former makes no sense, then neither does the latter. Making
some sort of special case where, suddenly, integers are not immmediate
values strikes me as not very sugary :)


David
 
J

Jean-Hugues ROBERT

About ++ & += operators...

Well, I'll take your word for it, but apparently Matz is keeping them
secret :) I'm just summarizing the reasons Matz has talked about in
the past (the illogic of incrementing integers, which are unique and
immutable, and which are present as immediate values in the variables
that represent them).

That there would be other reasons does not mean that I know what
they are ;-)
Of course the parser could be taught to do what you describe -- it's
just that it wouldn't make sense. Keep in mind that these two things
are equivalent:
1++
and
x = 1
x++
so if the former makes no sense, then neither does the latter. Making
some sort of special case where, suddenly, integers are not immmediate
values strikes me as not very sugary :)
David

I agree that
1 += 1
does not make much sense, yet
x = 1
x += 1
does make some sense.
I am not advocating for special cases when I assume that some kind
of lvalue exists, or am I ?

Jean-Hugues
 
H

Hal Fulton

Jean-Hugues ROBERT said:
Well... something++ could get expanded into (something = something.++()) ?
And ++something get expanded into (tmp = something, something =
something.++(), tmp)
Pure syntax sugar.
Then you can:
def ++()
self + 1
end
I think += does that already, doesn't it ?
There are other reasons why there is no ++ in Ruby.

Well, my impression is that Matz doesn't like for assignment to be
done except where it's painfully obvious there's an assignment.

Assignment is not considered a true operator in Ruby. (Yes, it has
precedence, but it operates on variables, not on objects.)

But we are used to thinking of ++ and -- as operators, not as
assignment.

This may be part of the reason. But IANYM.

Also IMO these operators can encourage some obfuscated code which
would be better written another way. Of course, both parts of my
statement are debatable.


Hal
 
J

Jean-Hugues ROBERT

About ++ ...
Just like +=, ++ can not be defined as a method on an object.

but + can be redefined and ++ could as well. As a matter of fact
one may argue that even ++pre and ++post could be redefined (but
I am certainly not going to advocate for that).
But you are correct that there is no /technical/ reason preventing ++a
from being treated an abbreviation for a=a+1.

I suspect that there *are* technical reasons. I would have to dig in
the lexer/parser code to figure out what they are I suppose.
However, one must balance the advantages against the disadvantages. Does
the convenience make up for the complexity of yet more special syntax.
Does it fit well with the rest of the language? (for example: += works
well with strings, what should ++ do with strings? What should ++ do with
time values: increment by an hour, a minute, a second, a day?).

++ is a nice idiom. I remember how happy I was when I eventually figured
it out while learning C. Remember:
strcpy( char* dest, char *src ) { while *dest++ = *src++ }
Much the same nostalgia with a->b shorthand for (*a).b !
That one will be in ruby 2 somehow: key: value for :key => value
L'histoire est un éternel recommencement.
history is an eternal rebeggining (sorry for that)
In this matter of balance, everyone will weigh the sides differently. So
far, Matz has decided that the convenience of saving one character doesn't
balance the extra complexity involved. So be it. Many people agree, some
people dont'. I can live with that (and I'm glad it is Matz deciding and
not me!).

So do I :)

Jean-Hugues
 
J

Jean-Hugues ROBERT

Jean-Hugues ROBERT said:

+ is a method. It is sent to an object. (e.g. 1+2 === 1.+(2) )

= is not a method. It is never sent to an object. It binds objects to
names within a scope. (e.g. x=1 means that the name "x" is now bound
to the value "1")

++ cannot be a method because it changes bindings, just like =.
Let me rephrase.
If ruby was to understand:
this++
++that
as (syntax sugar for):
(tmp = this, this = something.postplusplus(), tmp)
(that = that.preplusplus())
then one could redefine methods postplusplus() and preplusplus()
(whose default definitions should be: self.plusplus(); in a decent world).

I understand that = is not a method as of today. And need not to
be for ++ to be re definable (as rephrased).

BTW: Making = a method (of class Binding I guess) would open
interesting perspectives... ;-)

Jean-Hugues
 
M

Mark Hubbart

Let me rephrase.
If ruby was to understand:
this++
++that
as (syntax sugar for):
(tmp = this, this = something.postplusplus(), tmp)
(that = that.preplusplus())
then one could redefine methods postplusplus() and preplusplus()
(whose default definitions should be: self.plusplus(); in a decent
world).

I understand that = is not a method as of today. And need not to
be for ++ to be re definable (as rephrased).

IMHO, *if* it was decided to add ++ and -- to the language, it should
be made obvious that ++ is not a method. Instead of translating var++
to var += 1, or defining a #++() method, it should replace the contents
of var with var.succ, or var.pred. It might translate something like
this:

print var++
print var--
print ++var
print --var

becomes the equivalent of:

print lambda{|tmp|tmp=var;var=var.succ;tmp}[nil]
print lambda{|tmp|tmp=var;var=var.pred;tmp}[nil]
print (var = var.succ)
print (var = var.pred)

Then all that would be needed would be to implement #succ and #pred for
any object, and you can ++ and -- your heart out.

It should be pointed out out that var++ is *not* equivalent to var +=
1, as someone suggested. var++ returns the original value of var, then
sets it to the incremented value.
BTW: Making = a method (of class Binding I guess) would open
interesting perspectives... ;-)

!!! I *really* hope that was a joke! :)

cheers,
--Mark
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,145
Messages
2,570,825
Members
47,371
Latest member
Brkaa

Latest Threads

Top