In The Well Grounded Rubyist (which, along with The Ruby Way, I
love), Dave Black presents a justification for the x++ omission in
Ruby. I thought I'd see whether I could implement just the
incrementing portion of C's x++ functionality (without the prefix/
postfix issues) in pure Ruby. I wasn’t willing to delve into Matz’
implementation of higher-level Ruby functions or low-level C/C++
code. Below is what I came up with.
Q1. Test 1 failed, I imagine, because the interpret thought “Ah, 7’s
a Fixnum which I ‘ve seen billions of times, so I know what to do with
it.” Thus, it ignored my over-riding definition of Fixnum. So I
call it “compiler error”, to use the vernacular, by reporting that x
had no method “pp”. Am I all wet?
Test 2 passed, but it with a couple of anomalies:
Q2. x.to_s yielded x’s class and address, suggesting x had become a
“semi-Fixed Num”, i.e, x now stored a REFERENCE to the to x’s data,
rather than the immediate storage of the data, as interpreter is wont
to do with Fixnum’s. Am I all wet?
Q3. y.inspect yielded only it’s value (8) and nothing else,
suggesting the x.pp yielded a full-fledged Fixnum. Am I all wet?
Dave Black argues that since Fixnum values use immediate storage
rather than referenced storage, x=1;x++ would be akin to changing 1
into 2. This example somewhat supports that view, but the
interpreter sidestepped the matter by creating a reference for x’s
value and an immediate value for y (=x.pp).
Any ideas,
Richard
class FixNum
attr :val
def initialize (fixnum)
puts "Initializing object %d" % fixnum
raise "Initializer not a Fixnum" if
fixnum.class != Fixnum
puts "\nInitializing Fixnum to %d" % fixnum
@val = fixnum
end
def pp
@val+=1
end
end
# Test 1 (Failure)
x = 7; y = x.pp; z =x.class # undefined method `pp' for 7:Fixnum
(NoMethodError)
# Test 2 (Success)
x = FixNum.new(7); y = x.pp; z =x.class
puts [x.to_s, y.inspect, z.to_s].join("; ") # => <FixNum:0x2b62694>;
8; FixNum
Hi,
Please ignore my questions. I just discovered a major mistake: I
thought I was overriding Ruby's Fixnum class, but I misspelled it at
FixNum. That error invalidates most if not all of the things I
reported. Mea Culpa.
I'll correct my errors and probably have a new theory subsequently.
Best wishes,
Richard
> I'll correct my errors and probably have a new theory subsequently.
IMHO the story goes like this: absence of postfix ++ and -- is a
consequence of the fact that numeric types are immutable in Ruby which
makes an assignment necessary for these operators. Although that
would be doable, it would not immediately be obvious when looking at
"foo++". On the other side, "foo += 1" makes the assignment obvious
while still being pretty concise (you do not have to write "foo = foo
+ 1").
Which brings us to the question: what is the advantage of immutable
numbers? First, it avoids errors that could be caused by aliasing
(two objects refer the same object, one of them changes it, it changes
for the other one as well without being expected). Then, it is quite
natural if you consider mathematical numbers: they cannot change.
Additionally, the expression "1" can always refer to the same object
(in reality it's a bit different but from a Ruby programmer's
perspective the difference is not noticeable) which in fact makes
using numeric constants very efficient (as opposed to the expression
"'foo'" which constructs a new String instance on every invocation,
albeit with a shared char array underneath which eases the pain a
bit).
This in turn makes integer math pretty efficient because if numbers
were mutable Ruby would have to create a new object for every result
of an operator evaluation. I am not saying that Ruby is ideal for
number crunching but it could be significantly slower if certain
design decisions would have been made differently.
Kind regards
robert
--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
You could "decorate" it with such a method though. This could look
something like this:
class FixNum < BasicObject
def initialize(fn)
@fn = fn
end
def succ!
@fn += 1
end
def method_missing(*args, &block)
@fn.send(*args, &block)
end
end
a = FixNum.new(1)
a.succ!
p a
=> 2
Whether this is good practice or marginally useful ...
Hi lith,
can you extol your knowledge on me about what method_missing is doing?
I get what *args and &block is, but not quite sure what's going on?
> end
>
> a = FixNum.new(1)
> a.succ!
> p a
> => 2
>
> Whether this is good practice or marginally useful ...
>
>
--
Kind Regards,
Rajinder Yadav
Do Good! - Share Freely, Enrich and Empower people to Transform their lives
I think that theres a more fundamental problem with ++ in a language
like ruby, which has to do with the difference between objects and
variables.
The c ++ and -- operators change a variable, NOT a value.
so in C
a = 1
b = a
a++
a is now 2, but b is still 1.
Now, consider not immutable objects, but defining ++ for a mutable
object. I've named the method plus_plus instead of ++ since I can do
the former, but not the latter.
class String
def plus_plus
self << " plus a plus"
end
end
a = "A non-plussed string"
b = a
puts "a is #{a.inspect}"
puts "b is #{b.inspect}"
a.plus_plus
puts "a is #{a.inspect}"
puts "b is #{b.inspect}"
When we run this we see that the result is:
a is "A non-plussed string"
b is "A non-plussed string"
a is "A non-plussed string plus a plus"
b is "A non-plussed string plus a plus"
Because in languages like Ruby with object reference variable
semantics, methods can only operate on objects, not the variables
which reference them.
So if you COULD successfully define Fixnum#++, or Fixnum#plus_plus:
a = 1
a++
could only change the singleton instance of 1 into 2, which probably
isn't something you'd really want to do.
By 'you' I'm not aiming at you Robert.
This reminds me of a very hard bug I encountered years ago when I was
first was learning to program in Fortran. In the original Fortran you
could assign a new value to a subroutine parameter inside the
subroutine. If the actual parameter value was an integer literal, you
could literally change 1 to 2, and that's why I know you probably
don't want to do this.
--
Rick DeNatale
Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
(Not what that word means.)
> your knowledge on me about what method_missing is doing?
http://www.ruby-doc.org/docs/ProgrammingRuby/html/ref_c_object.html#Object.method_missing
Best,
--
Marnen Laibow-Koser
http://www.marnen.org
mar...@marnen.org
--
Posted via http://www.ruby-forum.com/.
How their behavior is defined is completely up to the language designer.
You could make "a++" syntactic sugar for
(_tmp = a; a = a + 1; _tmp)
in the same way as "a += 1" is syntactic sugar for "a = a + 1" or "a ||=
10" is syntactic sugar for "a || a = 10". In fact the sequence in
brackets above would be a completely reasonable way to do it in Ruby:
you could use "a++" in a similar way as in C++ and Java without
sacrificing Fixnum's immutability.
But: you would hide the assignment in the syntactic sugared version and
this could lead to unexpected behavior, like
a = 1
b = a
a++
# now why is b still 1???
For someone unaware of the hidden assignment but aware of the fact that
the object referenced by a must be mutable to make this work it would be
surprising that b is not changed as well. You could only discover that
by looking at #object_id of both (or using #equal?).
> so in C
>
> a = 1
> b = a
> a++
>
> a is now 2, but b is still 1.
Yes - and in C++ you can have it otherwise:
robert@fussel:~$ g++ x.cc && ./a.out
a++=1
a=2
b=2
robert@fussel:~$ cat x.cc
#include <stdio.h>
int main( int argc, const char* argv[] )
{
int a = 1;
int &b = a;
printf("a++=%d\n", a++);
printf("a=%d\n", a);
printf("b=%d\n", b);
return 0;
}
robert@fussel:~$
Not necessarily. If this was implemented in the language the sequence
"1" would be an object constructor in the same way as string "constants"
are.
robert@fussel:~$ ruby1.8 -e '2.times { puts "foo".object_id }'
-605970738
-605970758
That would the only reasonable way to do it. Then there would be no
singleton instance which in turn would have the said performance
implications.
I would consider the example from Fortran that you presented (changing
the value of the constant 1) rather a bug either in the language
implementation or in the design. This does not mean that other
languages would have to repeat that. :-)
> Yes - and in C++ you can have it otherwise:
>
> robert@fussel:~$ g++ x.cc && ./a.out
> a++=1
> a=2
> b=2
> robert@fussel:~$ cat x.cc
>
> #include <stdio.h>
>
> int main( int argc, const char* argv[] )
> {
> int a = 1;
> int &b = a;
> printf("a++=%d\n", a++);
> printf("a=%d\n", a);
> printf("b=%d\n", b);
> return 0;
> }
No, you can't:
$ ./ab
a: 2 @ 0xbfe413f8
b: 2 @ 0xbfe413f8
$ cat ab.cc
#include <iostream>
int main(void) {
int a = 1;
int &b = a;
a++;
std::cout << "a: " << a << " @ " << &a << std::endl;
std::cout << "b: " << b << " @ " << &b << std::endl;
return 0;
}
There is only one variable, b is just another name for it.
mfg, simon .... l
I think it would make more sense, if you were going to define a "++"
syntax for Ruby, to use "a.succ" rather than "a+1", and if you are
going to create syntax which does an assignment but returns the
pre-assignment value of the variable receiving the assignment, I'd go
further and include a more general form for that, say ":=", such that
"a := b" is equivalent to "(_ = a),(a = b), _" and then define postfix
"++" such that "a++" is "a := a.succ" and prefix "++" such that "++a"
is equivalent to "a = a.succ".
> How their behavior is defined is completely up to the language designer.
> You could make "a++" syntactic sugar for
>
> (_tmp = a; a = a + 1; _tmp)
>
> in the same way as "a += 1" is syntactic sugar for "a = a + 1" or "a ||= 10"
> is syntactic sugar for "a || a = 10". In fact the sequence in brackets
> above would be a completely reasonable way to do it in Ruby: you could use
> "a++" in a similar way as in C++ and Java without sacrificing Fixnum's
> immutability.
And I would argue that you still can't implement ++ for fixnum since
there isn't a ++ method, any more than there is a += method.
> But: you would hide the assignment in the syntactic sugared version and this
> could lead to unexpected behavior, like
Which I think gets to the fundamental difference.
In C/C++ an integer variable is just a bit-string of a particular
length interpreted as a signed (probably 2s complement) integer, and
++ is a operator on the variable which twiddles those bits.
In Ruby and languages of its ilk, a variable is a reference to an
object, and can only be modified by an assignment, not by a method of
the object it happens to be referencing at the moment, whether that
object is mutable or not.
I'm not going to run the experiment, but I believe that if the
int &b = a;
were changed to
int b = a;
Then the result would be the same as in Robert's 'surprising' ruby example.
Which only points out the different in meaning between a C 'reference'
variable, which aliases another variable, and the concept of a ruby
variable as a reference to an object.
And no, I don't think that adding syntactic sugar to Ruby to make a++
the same as either
a += 1
or
a = a.succ
is a good idea.
As a matter of fact, neither of this is REALLY the same as a++, since
things like
b = a++
should assign the ORIGINAL value of a to b, as opposed to
b = ++a
Things like post and pre increment/decrement operators in C like
languages are best reserved to languages with the same basic
structure.
To my mind they are akin to the different rules for gender, and
agreement in different families of languages.
Hi Robert,
Thank you for your thoughtful and extensive responses. I apologized
earlier for my sloppy analysis. I hope the following offers higher
quality.
(a) You say, in part:
“... immutable numbers? First, it avoids errors that could be caused
by aliasing (two objects refer the same object, one of them changes
it, it changes for the other one as well without being expected”
(b) Dave Black, in his truly excellent “The Well-Grounded Rubyist”
says, in part:
“Any object that’s represented as an immediate value is always exactly
the same object” and
“The reason [there’s no x=1; x++] is that , due to the immediate
presence of 1 in x, means you’d be changing 1 into 2,
and that makes no sense”
1. I’d rather discuss this matter in concrete terms rather than
abstractions. Please look at the following method (to generate
results) and two statements:
def show(v)
"Got #{v}, class = #{v.class}, object_id = #{v.object_id}
(v.object_id-1)/2 = #{(v.object_id-1)/2 }"
end
a = 1; show (a) => Got 1; class = Fixnum; object_id = 3; v >> 1
= 1
b = 1; show (b) => Got 1; class = Fixnum; object_id = 3; v >> 1
= 1
a == b => true
Both “a” and “b” have their respective values held as immediate values
(embedded in their object_id’s), but they are NOT the same thing
because they’re ultimately held in their respective entries in the
symbol table. So, object_id’s for Fixnum’s are synthetic. To think
that those object_id’s point to a location in a memory area that
stores the 32-bit 000...001 (in a 32-bit machine/OS) is to contradict
the meaning of immediacy and defeat the very efficiency that immediate
values offer.
2. Now please consider the following supplement to the statements
above:
a += 1; show (a) => Got 2; class = Fixnum; object_id = 5; v >> 1
= 2
show (a) => Got 2; class = Fixnum; object_id = 5; v >> 1 = 2
show (b) => Got 1; class = Fixnum; object_id = 3; v >> 1 = 1
The assignment of “a += 1” to “a” changed a’s object_id to embed a new
value: 2. Despite that change of 1 to 2 in a’s object, “b” remains
set to 1. “b” did not suffer the calamity of a universal change of
all Fixnum 1’s to 2’s.
3. Conclusion:
a += 1 is equivalent to a++’s natural meaning. In fact, we further
supplement the above statements with:
class Fixnum
def pp # We can’t define ++ because of a compiler restriction.
self + 1
end
end
a=1; show(a.pp) => Got 2; class = Fixnum; object_id = 5; v >> 1
= 2
show(b) => Got 1; class = Fixnum; object_id = 3; v >> 1 = 1
Furthermore, pp works fine on the boundary condition for Fixnum’s on a
common 32-bit cpu/OS, i.e. 2**30-1:
a = 2**30-1; show (a) => Got 1073741823; class = Fixnum; object_id
= 2147483647; v >> 1 = 1073741823
a = 2**30; show (a) => Got 1073741824; class = Bignum; object_id =
22737670; v >> 1 = 11368835
So x++ works fine in the form of pp for positive Fixnum’s. I assume
it’ll work fine for non-positives, also.. A compiler change to allow
“def ++” is necessary to finally add ++ to Fixnum.
Again, thanks for your responses to my question.
Best wishes,
Richard
On Fri, Oct 30, 2009 at 12:03 PM, Rick DeNatale <rick.d...@gmail.com>wrote:
> I think that theres a more fundamental problem with ++ in a language
> like ruby, which has to do with the difference between objects and
> variables.
>
Personally I see nothing interesting about the behavior of ++ in any mutable
state language.
> Now, consider not immutable objects, but defining ++ for a mutable
> object. I've named the method plus_plus instead of ++ since I can do
> the former, but not the latter.
>
How is ++ any different from << except for << taking an argument? (given
hypothetical C-like ++ behavior)
There is already extensive precedent in Ruby for destructive method calls
that mutate state, and they all lead to the same confusion.
There is nothing interesting with Ruby in this regard, except that Ruby does
seem to go out of its way to do things immutably by default, which, in my
opinion, is pretty cool. But in the end Ruby is still very much a mutable
state language.
--
Tony Arcieri
Medioh/Nagravision
> a += 1 is equivalent to a++’s natural meaning. In fact, we further
> supplement the above statements with:
>
> class Fixnum
> def pp # We can’t define ++ because of a compiler restriction.
> self + 1
> end
> end
> So x++ works fine in the form of pp for positive Fixnum’s. I assume
> it’ll work fine for non-positives, also.. A compiler change to allow
> “def ++” is necessary to finally add ++ to Fixnum.
No x++ doesn't work fine if you want it to act like C's post-increment operator.
Let's leave Ruby aside for a moment and consider this snippet of C code.
int a = 1;
int b = a++
After these two lines a is 2, and b is 1, since a++ returns the
original value of a and then increments a.
Why this wierd semantic? Because it the original use case was for
pointers rather than integers, and it goes back to C originating
originally as a kind of high level assembly language for the DEC
PDP-11 which had postincrement and predecrement addressing modes used
for stepping through strings or arrays.
Because pre-ANSI C allowed easy spoofing/overlay of types, it also
worked for integers and was used in contexts like for loops
for(i = 0; i < max;i++)
where the value of the expression i++ was never used, only the side
effect that it left a as 1 higher than before was important.
Because of this, many C/C++ programmers seem to be unaware or forget
that the value of a++ is a, not (a+1). In fact Bjarne Stroustrup used
to rib himself by pointing out that the value of C++ was exactly the
same as C, because he IS certainly aware of the semantics.
Now what happens if we translate my initial snippet into Ruby using
your pp method
class Integer
# Not need to restrict to FixNums is there
# Name it pp since ++ isn't a valid Ruby method selector
def pp
self + 1
end
end
a = 1
b = a.pp
puts "a is #{a}, b is #{b}"
Produces not "a is 2, b is 1" as it would if it correctly implemented
C language semantics but
a is 1, b is 2
just the opposite of what would be expected by a C/C++ programmer who
understood the meaning of post-increment ++
The fact of the matter is that you can't write a ++ or a pp method in
Ruby which works like the C post-increment because it requires the
method to change the value of a variable which is bound to the object
and the method only knows what the object knows and the object doesn't
know which variable(s) refer to it.
consider
a = b = c = 1
b.pp
There are at least 3 variables which refer to the Fixnum object 1, The
fact that that reference is through a special form object id computed
by multiplying 1 by 2 and adding 1, as it is in several Ruby
implementations, is irrelevant. So is the fact that Fixnums happen to
be immutable. No object knows what variables reference it, and
wouldn't have a way to directly change those variables bindings
anyway.
The rebinding of a in
a = a.pp
doesn't happen in the pp method it happens in the calling context
because of the assignment expression there.
So if you just want a ++ which returns the incremented value of a
fixnum then you can write it as pp, but you really don't need to since
Integer#succ does just that.
If you want the real semantics of the C/C++ post-increment operator,
I'm afraid you'll have to look for it in a C family language, not an
object reference semantic language like Ruby.
Apparently apocryphal -- the increment usage predates the PDP 11 port
of C. (Interestingly, there's now a ton of sources repeating the story,
but so far as I know, the canonical answer from Ritchie and Thompson
was that the increment operator predates C proper, and thus the PDP 11
work.)
> Because pre-ANSI C allowed easy spoofing/overlay of types, it also
> worked for integers and was used in contexts like for loops
> for(i = 0; i < max;i++)
It is not because of spoofing or overlay of types that this worked,
but because the operator's defined for all types.
> If you want the real semantics of the C/C++ post-increment operator,
> I'm afraid you'll have to look for it in a C family language, not an
> object reference semantic language like Ruby.
This part, though, I totally agree with. It's not coherent to imagine a
++ operator, especially a postincrement, working in a Ruby-like language.
-s
--
Copyright 2009, all wrongs reversed. Peter Seebach / usenet...@seebs.net
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
Maybe I am missing something but how would one print a variable and
increment it with the same statement? In C one would just write printf
("%i/n", x++). I haven't seen any easy way to do this with Ruby. Using
<< or +=1 you have to have a separate statement for the assignment. So
instead of having something like:
i = 1
while (i < 10)
puts i++
end
you have to have:
i = 1
while (i< 10)
puts i; i +=1
end
I can see a reason for not being able to do 2++, but not i++.
On Tue, Nov 3, 2009 at 10:30 PM, Michael W. Ryder <_mwry...@gmail.com>wrote:
> Maybe I am missing something
>
Yes, maybe you're missing that I support a unary ++ operator :)
I can see the wisdom in not having it there to begin with though. I see the
++ operator as something almost inextricably tied to for loops in C. Ruby
provides better looping mechanisms, like the various Enumerable methods that
take blocks! Perhaps Matz didn't include a unary ++ operator as
encouragement to use better looping constructs in your code. If that's the
case, I think he certainly succeeded.
--
Tony Arcieri
Medioh/Nagravision
Yes, a++ and ++a could easily be rewritten by the parser into the
appropriate increment+set of a and the expression either returns the
incremented value or the non-incremented value. And I would like to
see that added. It doesn't fundamentally change the expectations of
the programmer, and it provides a one-character-shorter version of
a+=1. There's really no reason it shouldn't be added, because even in
Java or C, you are *never* modifying arbitrary references to that
value...you are *always* re-assigning the value a given variable
points to.
This example:
a = 1
b = a
a++
Would cause exactly the same results in every language I've worked
with...b would be 1 and a would be 2. The ++ operator never modifies a
value, it modifies what value the variable has assigned to it. If it
were modifying a value, then using ++ to bump a pointer through memory
offsets would have horrible side effects for anyone else assigned that
pointer value.
I have seen no convincing argument as to why ++ is not supported in Ruby.
- Charlie
Wouldn't it be cool if ruby had macros?
No.
There's no reason it _should_ be added. That's the reason it
shouldn't be.
> I have seen no convincing argument as to why ++ is not supported in Ruby.
You've got the onus the wrong way around.
And adding C-like operators based on a partiular assembly language to
any 21st century language, especially a high-level one, just seems
absurd!
Extra documentation so we can save three characters (a++ instead of a
+= 1) in a rare use case? No thanks!
--
Gavin Sinclair
It would, I think, be quite anomalous, since it would be the only case
(that I can think of anyway) of an assignment expression that didn't
look and feel like an assignment expression.
I'm also not sure what problem it would be solving, other than adding
to the "make <language> users feel at home in Ruby" effect. But I tend
to think that Ruby should move away from, not towards, doing things
for exclusively that reason.
David
--
The Ruby training with D. Black, G. Brown, J.McAnally
Compleat Jan 22-23, 2010, Tampa, FL
Rubyist http://www.thecompleatrubyist.com
David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com)
>> I have seen no convincing argument as to why ++ is not supported in Ruby.
>
> It would, I think, be quite anomalous, since it would be the only case
> (that I can think of anyway) of an assignment expression that didn't
> look and feel like an assignment expression.
>
> I'm also not sure what problem it would be solving, other than adding
> to the "make <language> users feel at home in Ruby" effect. But I tend
> to think that Ruby should move away from, not towards, doing things
> for exclusively that reason.
+2 (Thanks for the well formulated reasoning, David!)
Certainly it could be implemented in an extension to the language as
syntactic sugar much as += and it's family.
But I maintain, that it can't be implemented as a method, any more
than += or ||= could be.
If Matz deigned to do such a language change, I'd certainly feel free
to ignore it. <G>
I can't help but think of Alan Perlis' quip that "syntactic sugar
causes cancer of the semicolons"
I believe you are quite wrong. If a destructive function like gsub! can
be implemented as a method, then I see no reason that +=, |=, or postfix
++ couldn't be.
>
> If Matz deigned to do such a language change, I'd certainly feel free
> to ignore it. <G>
Well, as others have pointed out, Ruby's preference for iterators rather
than loops makes ++ a lot less useful. I use it a lot in PHP, but I
really haven't missed it in Ruby.
>
> I can't help but think of Alan Perlis' quip that "syntactic sugar
> causes cancer of the semicolons"
Cute. Of course, at some level, every programming language is syntactic
sugar...
>
> --
> Rick DeNatale
>
> Blog: http://talklikeaduck.denhaven2.com/
> Twitter: http://twitter.com/RickDeNatale
> WWR: http://www.workingwithrails.com/person/9021-rick-denatale
> LinkedIn: http://www.linkedin.com/in/rickdenatale
Best,
gsub! is implemented as a method on objects which contain data. ++ would
have to be implemented as a method on objects which ARE their data -- which
have no distinction between the object and its "contents".
gsub! can work because somewhere inside the object there is a hunk of storage
which is separate from the object itself. Fixnum has no such storage to
refer to.
I don't think ruby makes the distinction between native types &
objects à la java. I don't know the ruby source but from a glance at
numeric.c[1], I'd say it is handled as VALUE/ruby object like any
other object. All those numeric methods seem to convert the VALUE to c
numbers, do what they are supposed to do and then convert them back
again. Please correct me if I'm wrong and if you know the ruby source
code.
I don't think ruby is in need of such an operator but I don't see why
ruby shouldn't have macros to let people fake such a thing if they
deem it necessary.
[1] http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/numeric.c?view=markup
In message "Re: Ruby doesn't implement x++ for Fixnum's because ???"
on Wed, 4 Nov 2009 23:31:46 +0900, Marnen Laibow-Koser <mar...@marnen.org> writes:
|I believe you are quite wrong. If a destructive function like gsub! can
|be implemented as a method, then I see no reason that +=, |=, or postfix
|++ couldn't be.
Only if you accept the language that can change the value of 1 to 2.
I don't.
matz.
> I don't think ruby makes the distinction between native types &
> objects � la java.
Everything is an object.
Not every object contains separate storage.
When you write "a = 1; b = 1;", a and b do not refer to two separate objects
which happen to have the same numeric value; they refer to a single object
which has an immutable numeric value. You can't increment that value.
Hmph. Fortran can change constants, why's Ruby so much less powerful?
:)
-s
p.s.: Thanks much for providing such an enjoyable language.
On Wed, Nov 4, 2009 at 3:55 AM, Gavin Sinclair <gsin...@gmail.com> wrote:
> You've got the onus the wrong way around.
>
> And adding C-like operators based on a partiular assembly language to
> any 21st century language, especially a high-level one, just seems
> absurd!
>
> Extra documentation so we can save three characters (a++ instead of a
> += 1) in a rare use case? No thanks!
>
I think you're missing why ++ could be useful, and it's precisely because
Ruby is a "21st century language"
The ++ operator, far more than just being syntactic sugar for +=1, would
allow you to send an "increment" message to any object, which would change
its value in place, i.e.
def ++
incrementing_logic_goes_here
end
I could see this as being handy
--
Tony Arcieri
Medioh/Nagravision
And how exactly would you change the value of 1 in place?
martin
Hi David,
First, Thank you for The Well-Grounded Rubyist. I study like other
pour over scriptures or the Koran. Your topics are well chose,
beautifully explicated. And Manning adding typesetting that enhanced
the your work.
I started this thread because some of your comments on page 54, e.g.
"The un-reference ..." were a blemish among your excellent analyses.
The fact that Robert Klemme, whom I also respect highly as a Rubyist,
agrees with you gives me pause.
But nevertheless, I maintain that my corrected post of today refutes
such claims as "... any object that's represented as an immediate
value is always the same object." Russel & Whitehead dealt with this
kind of issue perhaps a century ago when the defined the first Natural
Number, 1, as "the set of all sets that are in one-to-one
correspondence with the set containing the Null Set." Plato dealt with
this in The Parable of the Caves" with the claim that allegedly
concrete things were merely reflections of the "real" objects.
I'm not clamoring for a Ruby implementation. I only posted my
analysis on this issue to get other people's opinions. And I find it
hard compose a mistake free exposition, e.g. the last code lines in
yesterday evening's post:
a = 2**30-1; show (a) => Got 1073741823; class = Fixnum; object_id
= 2147483647; v >> 1 = 1073741823
a = 2**30; show (a) => Got 1073741824; class = Bignum; object_id =
22737670; v >> 1 = 11368835
should have read:
a = 2**30-1; show (a) => Got 1073741823; class = Fixnum; object_id
= 2147483647; v >> 1 = 1073741823
show(a.pp) => Got 1073741824; class = Bignum; object_id =
22738520; v >> 1 = 11369260 # Of course, "v >> 1" is irrelevant
here
to make the point that "pp" crossed the Fixnum/Bignum boundary
smoothly.
Bottom line: Please keep up you great work! I appreciate it very
much!
Best wishes,
Richard
On Wed, Nov 4, 2009 at 10:23 AM, Martin DeMello <martin...@gmail.com>wrote:
> And how exactly would you change the value of 1 in place?
>
You don't. Are you insinuating the behavior of Fixnums isn't already
special cased to begin with?
--
Tony Arcieri
Medioh/Nagravision
On Wed, Nov 4, 2009 at 10:23 AM, Martin DeMello <martin...@gmail.com>wrote:
> And how exactly would you change the value of 1 in place?
>
Another way to look at it: does Fixnum#+ change the value of its receiver?
--
Tony Arcieri
Medioh/Nagravision
a = 1
a.class #Fixnum
a++ # a is now 2
1.class #Fixnum
1++ # Illegal
So although a is a Fixnum, and 1 is a Fixnum, they respond to ++ differently?
>
> --
> Tony Arcieri
> Medioh/Nagravision
>
--
Paul Smith
http://www.nomadicfun.co.uk
> ++ would have to be implemented as a method on objects which ARE their data
Not true. Check out the following, step by step:
def show(v)
"Got #{v}, class = #{v.class}, object_id = #{v.object_id}
(v.object_id-1)/2 = #{(v.object_id-1)/2 }"
end
class Fixnum
def pp # We can’t define ++ because of a compiler restriction.
self + 1
end
end
These lines show that a & b values are stored in there object_ids held
in the symbol table.
Don’t believe it? Read more.
a = 1; show (a) => Got 1; class = Fixnum; object_id = 3; v >> 1
= 1
b = 1; show (b) => Got 1; class = Fixnum; object_id = 3; v >> 1
= 1
a == b => true
Appending these lines shows that a & b values are distinct.
That is, after incrementing, a =2, b is unchanged; b is not
impacted by a’s change
a += 1; show (a) => Got 2; class = Fixnum; object_id = 5; v >> 1
= 2
show (b) => Got 1; class = Fixnum; object_id = 3; v >> 1 = 1
Appending these lines shows the ++’s alias pp works just find
a=1; show(a.pp) => Got 2; class = Fixnum; object_id = 5; v >> 1
= 2
show(b) => Got 1; class = Fixnum; object_id = 3; v >> 1 = 1
Appending these lines show that ++ crosses the Fixnum/Bignum boundary
a = 2**30-1; show (a) => Got 1073741823; class = Fixnum; object_id
= 2147483647; v >> 1 = 1073741823
show(a.pp) => Got 1073741824; class = Bignum; object_id =
22738520; v >> 1 = 11369260 # “v >> 1” is irrelevant, of course.
Do you agree?
Best wishes,
Richard
But you already can with the mechanics of the language that are already
present!
irb(main):003:0> i=15
=> 15
irb(main):004:0> i=i.succ
=> 16
irb(main):005:0> i="15"
=> "15"
irb(main):006:0> i=i.succ
=> "16"
irb(main):007:0> i=1.2
=> 1.2
irb(main):008:0> i=i.succ
NoMethodError: undefined method `succ' for 1.2:Float
from (irb):8
from /usr/local/bin/irb:12:in `<main>'
In an object that it makes sense to increment, define the #succ method!
It's that easy!
This doesn't seem to do the right thing.
a = 1
a.pp
Is a now 2? If not, you haven't implemented an increment operator.
> Appending these lines shows that a & b values are distinct.
> That is, after incrementing, a =2, b is unchanged; b is not
> impacted by a?s change
> a += 1; show (a) => Got 2; class = Fixnum; object_id = 5; v >> 1
>= 2
> show (b) => Got 1; class = Fixnum; object_id = 3; v >> 1 = 1
Right. You've changed which object a refers to, because you've reassigned
a.
> Appending these lines shows the ++?s alias pp works just find
> a=1; show(a.pp) => Got 2; class = Fixnum; object_id = 5; v >> 1
>= 2
> show(b) => Got 1; class = Fixnum; object_id = 3; v >> 1 = 1
Not the same. The key is that, after "a += 1", not only do you get 2,
but a is now 2.
> Do you agree?
No.
For "a.pp" to be the same as a++ in other languages, you'd have to do:
a = 1; a.pp; show(a) => Got 2
If you don't get a "2" by using a.pp, it's not an increment, just a "one
more than".
Consider a loop:
a = 1
while ((a += 1) < 10) do
puts a
end
Now, try:
a = 1
while (a.pp < 10) do
puts a
end
Doesn't do the same thing.
-s
--
yes, i see your point, but consider:
a = Foo.new()
b = a
c = 42
d = c
a++
p b
c++
p d
martin
>
> --
> Tony Arcieri
> Medioh/Nagravision
>
Hi Matz,
Thank you very much for your brilliant and enormous efforts in
creating Ruby and offering to the programming world as gift.
> Only if you accept the language that can change the value of 1 to 2.
I know that you know Ruby extremely well. But I have written the
following tests on this issue of whether "1" ever gets changed to
"2". I assume you have not looked at my post yesterday on this
issue. I'd be honored if you'd
look at the following comments and code and point out anything you
view as erroneous.
BTW, I'm not advocating x++ for Ruby. I'm just trying to understand
whether Ruby would literally change 1 to 2 as opposed to change a
variable that contains 1 to subsequently contain 2.
Best wishes,
Richard
def show(v)
"Got #{v}, class = #{v.class}, object_id = #{v.object_id}
(v.object_id-1)/2 = #{(v.object_id-1)/2 }"
end
class Fixnum
def pp # We can’t define ++ because of a compiler restriction.
self + 1
end
end
These lines show that a & b values are stored in their object_ids held
in the symbol table.
Don’t believe it? Read more.
a = 1; show (a) => Got 1; class = Fixnum; object_id = 3; v >> 1
= 1
b = 1; show (b) => Got 1; class = Fixnum; object_id = 3; v >> 1
= 1
a == b => true
Appending these lines shows that a & b values are distinct.
That is, after incrementing, a =2, b is unchanged; b is not
impacted by a’s change
a += 1; show (a) => Got 2; class = Fixnum; object_id = 5; v >> 1
= 2
show (b) => Got 1; class = Fixnum; object_id = 3; v >> 1 = 1
Appending these lines shows the ++’s alias pp works just find
a=1; show(a.pp) => Got 2; class = Fixnum; object_id = 5; v >> 1
= 2
show(b) => Got 1; class = Fixnum; object_id = 3; v >> 1 = 1
Appending these lines show that ++ crosses the Fixnum/Bignum boundary
> BTW, I'm not advocating x++ for Ruby. I'm just trying to understand
> whether Ruby would literally change 1 to 2 as opposed to change a
> variable that contains 1 to subsequently contain 2.
I am confused.
irb(main):001:0> 1.succ
=> 2
irb(main):002:0> 1.object_id
=> 3
irb(main):003:0> 1.succ.object_id
=> 5
irb(main):004:0>
Is that good enough? If not, I'd recommend taking a look at...
irb(main):004:0> 1.class
=> Fixnum
Fixnum .. Fixed number? :)
Variables don't contain values, they refer to objects. That's the
fundamental difference. So if you say, for instance
a = "hello world"
a.upcase!
a #=> "HELLO WORLD"
the message "upcase!" is sent to the *object* "hello world", not the
variable a. To see this:
a = "hello world"
b = a
a.upcase!
a #=> "HELLO WORLD"
b #=> "HELLO WORLD"
Fixnums are immutable objects; you can't have any method that changes
their value. Hence no ++
martin
i = 1
while (i < 10)
puts i.succ
end
the only way to get this to work is to use:
puts i; i = i.succ
which is not as clean as using puts i++.
Hi Peter,
> This doesn't seem to do the right thing.
>
> a = 1
> a.pp
>
> Is a now 2? If not, you haven't implemented an increment operator.
Thanks for this question. You're so right. I couldn't see it until
you pointed it out.
class Fixnum
def pp # We can’t define ++ because of a compiler restriction.
self + 1
end
end
doesn't change self (which Ruby won't allow for Fixnum's!!! Which, of
course, is why your:
a = 1
while (a.pp < 10) do
puts a
end
produces an infinite number of 1's ..., or would if RAM were infinite
and hardware addressing mechanisms were infinite.
I grateful for you taking the time to identify my deficiencies.
Best wishes,
Richard
I'd call it an oversight, not a personal failing.
It might make sense to want to be able to do
def pp()
old = self
self = self + 1
old
end
or something similar, but it's not well-defined. The problem is that
fundamentally, when you have two variables, a and b, which both contain
the object 1 (a Fixnum), there's no way to say "I want the object a points
to to change, but not the object b points to" *in a method call*. Because
the method call works on the object, not the variable.
-s
--
On Wed, Nov 4, 2009 at 11:21 AM, Paul Smith <pa...@pollyandpaul.co.uk> wrote:
> a = 1
>
> a.class #Fixnum
>
> a++ # a is now 2
>
> 1.class #Fixnum
>
> 1++ # Illegal
>
> So although a is a Fixnum, and 1 is a Fixnum, they respond to ++
> differently?
>
Why would 1++ be illegal? I'd think it would just evaluate to 1.
--
Tony Arcieri
Medioh/Nagravision
This is unidiomatic Ruby. In fact, it's becoming clear to me that just
about *any* use case for postfix ++ is unidiomatic Ruby. The cleanest
way *in Ruby* of doing what you did would be
(1..10).each {|i| puts i}
Incrementing is handled under the hood.
Best,
--
Marnen Laibow-Koser
http://www.marnen.org
mar...@marnen.org
On Wed, Nov 4, 2009 at 1:46 PM, Marnen Laibow-Koser <mar...@marnen.org>wrote:
> This is unidiomatic Ruby. In fact, it's becoming clear to me that just
> about *any* use case for postfix ++ is unidiomatic Ruby. The cleanest
> way *in Ruby* of doing what you did would be
>
> (1..10).each {|i| puts i}
>
> Incrementing is handled under the hood.
>
What if it's not?
m = CounterInMemcacheOrSomething.new :foobar
m++
--
Tony Arcieri
Medioh/Nagravision
What semantics do you intend here? I'm not sure I understand.
In any case, you have several perfectly good alternatives:
* use CounterInMemcacheOrSomething.all(:foobar).each{|m| ...}
* define CounterInMemcacheOrSomething#succ! if it's mutable
* or even use m += 1
++ is very useful in C-like languages and PHP. I thought it would be
useful in Ruby too, but I now believe that it wouldn't, since it's only
really good for stepping through structures -- and Ruby handles that
better with iterators.
I'd argue it's much, much cleaner. ++ has long been a source
of confusion for C programmers. Consider:
int i = 1;
while (i < 10)
{
printf("%d,",i++);
}
What does it ouput? 1,2,3,4,5,6,7,8,9, or 2,3,4,5,6,7,8,9,10,?
Because we're all experienced C programmers here we of course know
it to be 1,2,3,4,5,6,7,8,9, but it's not uncommon for experienced C
programmers to make mistakes around a++ vs ++a. On the other hand:
int i = 1;
while (i <10)
{
printf("%d,",i);
i+=1;
}
Makes it explicitly clear what is happening. Then consider the ruby
direct ruby translation:
i = 1;
while (i <10)
print "#{i},"
i+=1;
end
Even a non-programmer is going to have a pretty darn clear idea of
what is going on here. Sure it's one line longer but much more
understandable, and therefore cleaner. If there is one thing
playing Perl Golf should have taught all programmers it's that
shorter != better.
Now consider the ruby way:
10.times do |i|
print "#{i},"
end
Some length as the C code, but much more readable. Heck, it's
almost English! Which is part of the beauty of Ruby: It's simple,
natural, readable syntax. I've seen a lot of arguments that it
doesn't fit with ruby's object model, but to me that's not the key
point. ++ doesn't fit with Ruby's elegant syntax.
On Wed, Nov 4, 2009 at 2:41 PM, Marnen Laibow-Koser <mar...@marnen.org>wrote:
> What semantics do you intend here? I'm not sure I understand.
>
You can think of it like:
alias_method :++, :increment!
--
Tony Arcieri
Medioh/Nagravision
In message "Re: Ruby doesn't implement x++ for Fixnum's because ???"
on Thu, 5 Nov 2009 04:25:05 +0900, RichardOnRails <RichardDummy...@USComputerGurus.com> writes:
|BTW, I'm not advocating x++ for Ruby. I'm just trying to understand
|whether Ruby would literally change 1 to 2 as opposed to change a
|variable that contains 1 to subsequently contain 2.
There's no way to modify local variables by sending message in Ruby.
matz.
> Now consider the ruby way:
>
> 10.times do |i|
> print "#{i},"
> end
>
> Some length as the C code, but much more readable. Heck, it's
> almost English!
Not for me it wasn't. I had to try it to see that it actually works.
My initial impression was that it would print 10 copies of i. I still
don't see where 'i' is incremented so this is one of those "magical"
constructs much like your impression of ++ in C. I would find this much
harder to maintain than the C version.
Well, you do have to know what Numeric#times yields to its block. But
that's easy to look up. (However, it starts from 0, so it's not quite
equivalent to the C.)
> so this is one of those "magical"
> constructs much like your impression of ++ in C.
No. The "magic" is different. In the Ruby version, a quick check in
the API tells you that the counter is incremented each time through the
loop. In the C version, OTOH, you have to think about exactly where
you've put the ++, and whether you really wanted the value before or
after the increment.
> I would find this much
> harder to maintain than the C version.
Only because you apparently are not familiar with common Ruby idioms.
The Ruby version has a lot less to go wrong in it, because the language
transparently handles incrementing the "loop index" at the right time.
>
> Which is part of the beauty of Ruby: It's simple,
Yes. Just don't expect it to be much like C.
Whoop! Good point, that's what I get for not actually testing my code.
Corrected (and even closer to English).
(1..9).each do |i|
print "#{i},"
end
Michael Wrote:
> > Not for me it wasn't. I had to try it to see that it actually works.
> > My initial impression was that it would print 10 copies of i.
> I still don't see where 'i' is incremented
It isn't incremented, at least not in MY code (if you must think in
terms of incrementing variables, then Ruby is incrementing it for me)
See the times method at:
http://ruby-doc.org/core/classes/Integer.html
That kind of looping is a pretty core Ruby concept.
Also the corrected version I wrote above should be a bit clearer. Also
I think your previous programming experience is hurting you here. To you
as (I'm guessing) a C programmer, to progress in a loop, you must increment
modify variable. The average English speaker doesn't think in those terms.
Looking at my most recent example, the English equivalent would be for each
'i' from 1 to 9 print 'i' followed by a comma. Sure, the words may not be
in the precise order, but it comes a darn site closer to natural language than:
int i=1;
That version I understand just looking at it as it is equivalent to a
for loop. Your first version seemed more "magical" since I don't know
where 'i' is getting incremented. At least with C I know where the
incrementing is occurring.
> Michael Wrote:
>>> Not for me it wasn't. I had to try it to see that it actually works.
>>> My initial impression was that it would print 10 copies of i.
>> I still don't see where 'i' is incremented
>
> It isn't incremented, at least not in MY code (if you must think in
> terms of incrementing variables, then Ruby is incrementing it for me)
> See the times method at:
> http://ruby-doc.org/core/classes/Integer.html
> That kind of looping is a pretty core Ruby concept.
>
> Also the corrected version I wrote above should be a bit clearer. Also
> I think your previous programming experience is hurting you here. To you
> as (I'm guessing) a C programmer, to progress in a loop, you must increment
> modify variable. The average English speaker doesn't think in those terms.
>
I started with Fortran in the early 1980's, followed by Basic, Pascal,
Modula 2, and C. For over 25 years I have been mostly programming in
Business Basic. While Ruby has a lot of things going for it I miss some
of the features available in the other languages, especially the built
in curses and file handling in Business Basic.
What's wrong with
def inc
incrementing_logic_goes_here
end
How is that any different?
Maybe you'll just have to find another way to print the numbers 1 to
10 ;)
It can be done, if you are willing to make your numbers mutable:
class MutableNum
def initialize n
@n = n
end
def pp
@n += 1
@n - 1
end
def method_missing symbol, *args
@n.method(symbol).call(*args)
end
def to_s
@n.to_s
end
end
a = MutableNum.new 1
puts a.pp #=> 1
puts a #=> 2
Having said that, I agree with others that the post-increment operator
is not needed in Ruby at all.
--
Tobias Cohen
http://tobiascohen.com/
On Thu, 5 Nov 2009, Tony Arcieri wrote:
> On Wed, Nov 4, 2009 at 2:41 PM, Marnen Laibow-Koser <mar...@marnen.org>wrote:
>
>> What semantics do you intend here? I'm not sure I understand.
>>
>
> You can think of it like:
>
> alias_method :++, :increment!
But what would it mean to send the message increment! to, say, the
object 10? In the same vein:
>> 10.succ!
NoMethodError: undefined method `succ!' for 10:Fixnum
David
--
The Ruby training with D. Black, G. Brown, J.McAnally
Compleat Jan 22-23, 2010, Tampa, FL
Rubyist http://www.thecompleatrubyist.com
David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com)
I agree with David.. At which point are we completely violating the
principle of least surprise?
A number is a number is a number. It took me all of half an hour to
forget about ++ and I haven't looked back since. I -like- typing +=1
because it, simply put, makes sense.
On Thu, Nov 5, 2009 at 3:40 AM, Gavin Sinclair <gsin...@gmail.com> wrote:
> > def ++
> > incrementing_logic_goes_here
> > end
> >
> > I could see this as being handy
>
> What's wrong with
>
> def inc
> incrementing_logic_goes_here
> end
>
> How is that any different?
>
What's wrong with Array#push? Why do we need Array#<<? How is that any
different?
--
Tony Arcieri
Medioh/Nagravision
On Fri, 6 Nov 2009, Tony Arcieri wrote:
> On Thu, Nov 5, 2009 at 3:40 AM, Gavin Sinclair <gsin...@gmail.com> wrote:
>
>>> def ++
>>> incrementing_logic_goes_here
>>> end
>>>
>>> I could see this as being handy
>>
>> What's wrong with
>>
>> def inc
>> incrementing_logic_goes_here
>> end
>>
>> How is that any different?
>>
>
> What's wrong with Array#push? Why do we need Array#<<? How is that any
> different?
irb(main):001:0> [].push(1,2,3)
=> [1, 2, 3]
irb(main):002:0> [].<<(1,2,3)
ArgumentError: wrong number of arguments (3 for 1)
:-) But I know that's not what you meant. The thing is, a method
called ++ that did in-place incremention would not be meaningful for
numbers (if I understand correctly that you mean it would be similar
to succ!), and having it for other objects would probably just lead to
more confusion. That's my hunch, at least.
But Fortran fixed that bug in its first revision!
--
Rick DeNatale
Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
Apart from David's response, you're proposing that a currently-invalid
method name be allowed. For such a change, there needs to be a good
reason.
Gavin
On Thu, Nov 5, 2009 at 5:28 PM, David A. Black <dbl...@rubypal.com> wrote:
> The thing is, a method called ++ that did in-place incremention would not
> be meaningful for
> numbers (if I understand correctly that you mean it would be similar
> to succ!), and having it for other objects would probably just lead to
> more confusion. That's my hunch, at least.
There's no point at all if it doesn't work on numbers.
It would require special case behavior. Application to literal numbers
would be strange. But there's certainly no reason it can't be done, and you
have one Ruby implementer on this thread attesting that it can.
--
Tony Arcieri
Medioh/Nagravision
On Sat, 7 Nov 2009, Tony Arcieri wrote:
> On Thu, Nov 5, 2009 at 5:28 PM, David A. Black <dbl...@rubypal.com> wrote:
>
>> The thing is, a method called ++ that did in-place incremention would not
>> be meaningful for
>> numbers (if I understand correctly that you mean it would be similar
>> to succ!), and having it for other objects would probably just lead to
>> more confusion. That's my hunch, at least.
>
>
> There's no point at all if it doesn't work on numbers.
It depends how you define "work" :-) I'll stick with my formulation,
though: in-place incrementation of a numeric is not meaningful. So if
++ is understood to be in-place incrementation (like succ!), which is
how I interpreted your earlier post, then it wouldn't be meaningful
for numbers.
> It would require special case behavior. Application to literal numbers
> would be strange. But there's certainly no reason it can't be done, and you
> have one Ruby implementer on this thread attesting that it can.
It seems like a lot of special-casing and strangeness, though. I'm a
little bit hampered in discussing it, I guess, because I don't see
what benefit it would confer in exchange for the anomaly. So I'm
probably going in circles.
I have found a lot of idioms which are amenable to use with ++, especially
postincrement, but they are often not nearly so useful outside of the C-like
languages.
Consider the canonical inner loop for copying an array in C:
s[i++] = t[j++];
There's really no idiomatic equivalent -- nor a need for one, usually.
On Sat, 7 Nov 2009, Seebs wrote:
> On 2009-11-06, David A. Black <dbl...@rubypal.com> wrote:
>> It seems like a lot of special-casing and strangeness, though. I'm a
>> little bit hampered in discussing it, I guess, because I don't see
>> what benefit it would confer in exchange for the anomaly. So I'm
>> probably going in circles.
>
> I have found a lot of idioms which are amenable to use with ++, especially
> postincrement, but they are often not nearly so useful outside of the C-like
> languages.
>
> Consider the canonical inner loop for copying an array in C:
> s[i++] = t[j++];
>
> There's really no idiomatic equivalent -- nor a need for one, usually.
Oh, I have no problem with ++ per se. It just seems against the grain
in Ruby.
But if you wanted to do something like:
i = 10;
while (i > 0)
{
printf("%d/n", i--);
}
in Ruby you would have to do something like:
i = 10
while (i > 0)
puts i
i -= 1
end
As far as I can tell there is no way in Ruby to use .each or .times to
go backwards. While I realize this thread is about the ++ operator the
-- operator is complementary.
<snip>
No.
10.downto(1) do |i|
puts i
end
> As far as I can tell there is no way in Ruby to use .each or .times to
> go backwards.
That's what .downto is for. (Have you ever needed this? I have not.)
> While I realize this thread is about the ++ operator the
> -- operator is complementary.
>
> <snip>
Best,
what about the downto method?
Matt
On Sat, 7 Nov 2009, Marnen Laibow-Koser wrote:
> Michael W. Ryder wrote:
> [...]
>> But if you wanted to do something like:
>> i = 10;
>> while (i > 0)
>> {
>> printf("%d/n", i--);
>> }
>> in Ruby you would have to do something like:
>> i = 10
>> while (i > 0)
>> puts i
>> i -= 1
>> end
>
> No.
>
> 10.downto(1) do |i|
> puts i
> end
>
>> As far as I can tell there is no way in Ruby to use .each or .times to
>> go backwards.
>
> That's what .downto is for. (Have you ever needed this? I have not.)
And in 1.9:
puts *10.downto(1)
and there's also #reverse_each.
Yeah. I think fundamentally it's the "variables aren't objects" thing.
++ is intended to operate on a specific object, and doesn't make sense
if "x = x + 1" doesn't really mean "modify the specific object x".
I missed the downto method, I guess that is a problem when you have so
many different ways to do the same basic things. I much prefer the
simplicity of Basic and C with for loops that can go either direction.
As far as going backwards I use it a lot to parse strings of the form
"city name ST 12345-6789" to City, State, and Zip Code fields. I look
for the first blank from the end of the string and assume everything
after it is the Zip Code, I then find the next two non-blank characters
and assign them to State, and everything else is the City name.
I think one thing that's getting lost in the sauce here is that Ruby
does have idioms like:
a -= 1
for bumping things up and down and other operations. So you can
maintain a manual index on a collection or string traversal easily if
you need to. I'd say that most of the time, though, you won't need to.
That's because you're trying to write C in Ruby. There are far more
idiomatic ways of doing things -- and they *are* clearer, at least in a
Ruby context.
> As far as going backwards I use it a lot to parse strings of the form
> "city name ST 12345-6789" to City, State, and Zip Code fields. I look
> for the first blank from the end of the string and assume everything
> after it is the Zip Code, I then find the next two non-blank characters
> and assign them to State, and everything else is the City name.
That's great in a language like C that doesn't have very good string
handling. The Ruby way to do this would be
city, state, zip = string.split(/\s+/)
No incrementing. No iteration. Just a clear declarative syntax.
Best,
--
Marnen Laibow-Koser
http://www.marnen.org
mar...@marnen.org
Others have mentioned reverse each and downto, so I'll just throw in one
more. If you are determined to save that line, you also have:
(untested, so if I'm off my one, from the C feel free to tar and feather me)
i=11
while (i-=1) > 0
puts i
end
or:
i=11;
while i > 0
puts (i-=1)
end
I also think this demonstrates my previous point, that playing Perl golf
serves no one. I've found it rare that saving a line at the cost of
readability improves code in any way. If the interpreter is any good,
your 5 line example should execute just as fast as my 4 line, and it's
certainly much clearer what is actually being done. I've seen plenty of
C programmers who really should know better, get confused by ++ in
unexpected places.
What it all comes down to in my personal opinion (as no one of any real note)
is that while ++ can be a cool little operator, it really doesn't give enough
benefit to be worth the confusion involved in implementing it in Ruby. It's
been made plenty clear by others why ++ would have to be a special case operator
in Ruby (as opposed to the other operators which are simple methods), but why
write special logic for this one silly operator that at BEST saves us one line
of code here and there?
On Sat, 7 Nov 2009, Marnen Laibow-Koser wrote:
> Michael W. Ryder wrote:
> [...]
>> . I much prefer the
>> simplicity of Basic and C with for loops that can go either direction.
>
> That's because you're trying to write C in Ruby. There are far more
> idiomatic ways of doing things -- and they *are* clearer, at least in a
> Ruby context.
>
>> As far as going backwards I use it a lot to parse strings of the form
>> "city name ST 12345-6789" to City, State, and Zip Code fields. I look
>> for the first blank from the end of the string and assume everything
>> after it is the Zip Code, I then find the next two non-blank characters
>> and assign them to State, and everything else is the City name.
>
> That's great in a language like C that doesn't have very good string
> handling. The Ruby way to do this would be
> city, state, zip = string.split(/\s+/)
You'd need to take multi-word city names into account, though. So
maybe:
city, state, zip = /\A(.*)\s+(\S+)\s+(\S+)\Z/.match(str).captures
Quite right. I was trying for simplicity, but that had indeed crossed
my mind.
>
> David
>
> --
> The Ruby training with D. Black, G. Brown, J.McAnally
> Compleat Jan 22-23, 2010, Tampa, FL
> Rubyist http://www.thecompleatrubyist.com
>
> David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com)
Best,
Thanks for your response, Matz.
I've got to study David Black's book more thoroughly.
Best wishes,
Richard
On Fri, Nov 6, 2009 at 4:30 PM, Seebs <usenet...@seebs.net> wrote:
> "variables aren't objects"
I've seen this mentioned a few times. I think it's something of a gross
misstatement of a problem, and a deeper understanding might be able to peel
away some of the layers of the debate here.
I can't think of a language where "variables are objects". And this isn't
the issue. The real issue is Numeric values (i.e. "objects") are
immutable. Other types of objects, however, are mutable. "Everything is an
object", except some objects are different than others.
Advocates of allowing a ++ operator are suggesting that the operator have a
dispatch model which alters the local binding when applied to Numeric
types. I'm further suggesting it be dispatched like any other operator when
applied to non-numeric types.
What I really see happening here is that ++ reveals an otherwise
difficult-to-see difference in how immutable and mutable objects behave in
Ruby. There's no reason Ruby can't have ++, but it would need special case
behavior, because the behavior of Numerics is already a special case. Any
ugliness surrounding special-case behavior of ++ when implementing it
against Numerics stems from this inconsistency in Ruby itself, not the ++
operator.
It's not that I doubt the pragmatism of the immutability of Numeric values
(on the contrary, I'm developing a language where *all* values are
immutable), but this is really the cause of the problem, and the solution
(special casing how Numerics respond to ++ by providing alterations to the
local binding) causes me no qualms, as it's only a workaround of the
separation of immutable/mutable objects that's a fundamental part of Ruby to
begin with.
--
Tony Arcieri
Medioh/Nagravision
In C++ a variable can actually hold the state of an object rather than
simply a reference to the object.
If you think of object as simply meaning what holds the state of what
is denoted by a variable, then C variables hold objects, and since a
pointer represents state, even pointer's can be considered objects in
this degenerate (if you will) form.
And that really is the point with the ++ operator, at least if you
want it to have the semantics of C/C++.
the c/c++ expression
b = a++
has the meaning.
1) copy the current contents of the a variable to b
2) increment the contents of the variable a according to the static
type of a, e.g. if it's an int or a pointer to a char add 1 to it, if
it's a pointer to a (4-byte) int add 4 to it, etc.
The original quest in this thread was to do this by defining a ++
method for FixNum (or Integer).
As Matz himself has pointed out in this thread,
>
> There's no way to modify local variables by sending message in Ruby.
>
> matz.
Which is something I've said on this thread before (multiple times IIRC).
This has nothing to do with whether or not the object bound to a
variable is immutable, it has to do with how ruby variable bindings
can and cannot be changed, and that is the whole point.
Now, while it's true that Fixnums have a property of being represented
by an immediate value rather than a pointer to a 'boxed' value, and
this is possible because they are immutable, it doesn't mean that
local variables with non-immediate bindings can be rebound inside the
invocation of another method.
The only way to define b = a++. in Ruby with C/C++ semantics would be
to alter the parser to treat such expressions as syntactic sugar,
(which was Charle's proposal), much like += is handled now.
Let's say this were done, perhaps by the parser treating:
b = a++
as if it were
b, a = a, a.succ
much like it treats
a += 1
as if it were
a = a + 1
The actual parser changes would need to be sensitive to other cases like
foo(b + a++)
which would need to compute a + b before incrementing a.
One could alter what the increment did, by redefining succ or a
particular class, much like redefining + for a given class can alter
the value of a + 1 for a particular binding of a.
But one could still not move the actual change of binding into a
method, any more than you can redefine the '=' part of '+='
I'd say they are in C.
In C:
{
int x;
}
x is an object. There is storage which is reserved for x, which is not
associated with any other object, etcetera. Modifications "to x" always
affect this specific object; you can't make x be some other object, all
you can do is change its contents.
> And this isn't
> the issue. The real issue is Numeric values (i.e. "objects") are
> immutable. Other types of objects, however, are mutable. "Everything is an
> object", except some objects are different than others.
I think it is the issue though.
The reason you can write "x = x + 1" in Ruby, but not "x++", is that you
have to modify the variable, not the object. If x was previously the Fixnum
1, you don't want to change 1 to 2 -- you want to change x to point to a
different object. You can't do that by sending x a message, though, you
have to write it in the code that knows about the variable x.
> Advocates of allowing a ++ operator are suggesting that the operator have a
> dispatch model which alters the local binding when applied to Numeric
> types.
(1+2)++
1+2 => the Fixnum 3
What is the local binding which gets incremented? There's no variable there,
only an object.
> What I really see happening here is that ++ reveals an otherwise
> difficult-to-see difference in how immutable and mutable objects behave in
> Ruby. There's no reason Ruby can't have ++, but it would need special case
> behavior, because the behavior of Numerics is already a special case. Any
> ugliness surrounding special-case behavior of ++ when implementing it
> against Numerics stems from this inconsistency in Ruby itself, not the ++
> operator.
I don't entirely agree. The difference is most *obvious* with Numerics,
but it's true of just about anything.
Imagine that we define ++ on an array as equivalent to "a = a + [ nil ]".
That is, it appends a new value on the end of the array.
Now try setting up an array:
a = Array.new
b = a
a++
How many items does b have? Why, it now has an item, because there is only
one array. a and b are not arrays; a and b are variables which hold
references to a single array object.
What that means is that, while Numerics have special case behavior, *the
special case behavior is the one we actually want*.
Ignore the return value for a moment. Clearly, the *intent* of "a++" is
the same as the *intent* of "a = a + 1". But in Ruby, those aren't the
same thing.
a = Array.new
b = a
a = a + [ nil ]
This makes a and b into two separate objects.
> It's not that I doubt the pragmatism of the immutability of Numeric values
> (on the contrary, I'm developing a language where *all* values are
> immutable), but this is really the cause of the problem, and the solution
> (special casing how Numerics respond to ++ by providing alterations to the
> local binding) causes me no qualms, as it's only a workaround of the
> separation of immutable/mutable objects that's a fundamental part of Ruby to
> begin with.
I disagree, because I think it would violate POLS to have ++ work differently
on numerics, when clearly, that behavior (alters local binding) is exactly
what we want... Probably.
Again, I really think the root of this is that ++ is designed for a language
in which the variable is its own object, not a reference to another object.
Insofar as anything in C is "an object", pointers are.
On Sun, Nov 8, 2009 at 10:45 AM, Rick DeNatale <rick.d...@gmail.com>wrote:
> As Matz himself has pointed out in this thread,
>
> >
> > There's no way to modify local variables by sending message in Ruby.
> >
> > matz.
>
> Which is something I've said on this thread before (multiple times IIRC).
>
> This has nothing to do with whether or not the object bound to a
> variable is immutable, it has to do with how ruby variable bindings
> can and cannot be changed, and that is the whole point.
>
You still seem to be missing what I'm proposing.
For Numerics, ++ would rebind. For everything else, it would be dispatched
as a message.
Am I being unclear?
--
Tony Arcieri
Medioh/Nagravision
Yuuuuuuuck! Why do this ugly special-casing for something that's hardly
ever needed anyway?
>
> Am I being unclear?
No, just silly. :D
On Sun, Nov 8, 2009 at 11:22 AM, Marnen Laibow-Koser <mar...@marnen.org>wrote:
> Yuuuuuuuck! Why do this ugly special-casing for something that's hardly
> ever needed anyway?
>
To reiterate from my previous message, because the behavior of Numerics is
already a special case to begin with.
--
Tony Arcieri
Medioh/Nagravision
How? Because they are immutable? That's not special casing, that's just
how the class is designed. I can write an immutable class in Ruby,
without any special casing.
On Sun, Nov 8, 2009 at 11:50 AM, Rick DeNatale <rick.d...@gmail.com>wrote:
> No, but you ARE missing the fact that the lack of being able to rebind
> a variable via a method has NOTHING to do with the class of the object
> which is currently bound to that variable.
>
But the rebinding is being done by an operator, not a method, and there's
ample precedent for operators that perform rebinding in Ruby (=, +=, -=, /=,
etc)
--
Tony Arcieri
Medioh/Nagravision
> For Numerics, ++ would rebind. For everything else, it would be dispatched
> as a message.
> Am I being unclear?
I don't think that gives the right semantics in many cases. It's also
not clear that rebinding works:
array_example.length++
What should this do?
And which of those operators special-case Numeric?
Any of them? I don't think so.
If it's to be a rebinding operator, it ought to rebind for everything, not
just for numerics.
On Sun, Nov 8, 2009 at 11:49 AM, Walton Hoops <wal...@vyper.hopto.org>wrote:
> How? Because they are immutable? That's not special casing, that's just
> how the class is designed. I can write an immutable class in Ruby,
> without any special casing.
>
Yes, non-Numeric objects can be immutable. However, Numeric objects can't
be mutable.
--
Tony Arcieri
Medioh/Nagravision
On Sun, Nov 8, 2009 at 12:20 PM, Seebs <usenet...@seebs.net> wrote:
> I don't think that gives the right semantics in many cases. It's also
> not clear that rebinding works:
>
> array_example.length++
>
> What should this do?
>
Well, this is a very interesting question, as I discovered something about
Ruby I didn't know from this...
Say we have:
class Foo
attr_reader :bar
def initialize
@bar = 0
end
end
f = Foo.new
f.bar += 1
What do you think the value of a subsequent call to f.bar will be?
I was surprised to discover that it indeed 1. Somehow += is mutating the
ivar through a supposed "attr_reader" even though there is no corresponding
bar= method. In that case += appears to be frobbing the ivar directly.
Very strange. Even worse:
class Foo
def initialize
@bar = 0
end
def bar
@bar + 1
end
end
f = Foo.new
f.bar += 1
Now what do you think the value of a subsequent call to f.bar will be?
Indeed, it would be 3!
I cannot begin to answer this question because Ruby is doing strange and
unexpected things here, at least from my perspective...
--
Tony Arcieri
Medioh/Nagravision
On Sun, Nov 8, 2009 at 12:32 PM, Tony Arcieri <to...@medioh.com> wrote:
> I cannot begin to answer this question because Ruby is doing strange and
> unexpected things here, at least from my perspective...
>
Never mind, bar= was still defined because I was reopening the class.
So to answer your question:
array_example.length++
..would attempt to rebind through #length=, and fail if it weren't defined.
--
Tony Arcieri
Medioh/Nagravision
On Sun, Nov 8, 2009 at 12:20 PM, Seebs <usenet...@seebs.net> wrote:
> And which of those operators special-case Numeric?
>
> Any of them? I don't think so.
>
Admittedly it would be a first.
> If it's to be a rebinding operator, it ought to rebind for everything, not
> just for numerics.
To borrow a phrase from 37signals, "context is more important than
consistency"
--
Tony Arcieri
Medioh/Nagravision
Incorrect. In fact the very first message in this thread provided an
example of redifining Fixnum in such a way that it was mutable.