Too Many Ways?

G

Gavin Kistner

At what point do you cross over from:
"Various ways to accomplish the same goal is good,
because it allows the language to work the way
different people think about working."
into the land of:
"Duplicate names and techniques to do the same
atomic thing ends up confusing the nubys"
?

results = my_array.collect{ ... }
results = my_array.map{ ... }

a = Proc.new{ ... }
b = lambda{ ... }
def whee; ...; end
c = self.method( :whee )

def foo &blockAsBlock
blockAsBlock.call
yield
end

foo &a
foo &b
foo &c

def bar blockAsParam
blockAsParam.call
end

bar a
bar b
bar c

Regexp globals vs. MatchData
#insert your own examples here
 
G

Gavin Sinclair

At what point do you cross over from:
"Various ways to accomplish the same goal is good,
because it allows the language to work the way
different people think about working."
into the land of:
"Duplicate names and techniques to do the same
atomic thing ends up confusing the nubys"
?

[snip good examples]

AFAIC, there's no objective answer. I dislike the extremes in both
directions (that goes for any topic, really). Python is way too
strict for my taste. Ruby is pretty much fine, IMO. If I were king,
I'd tighten it up just a little, and probably screw the whole thing
up.

Gavin
 
R

Robert Klemme

Gavin Kistner said:
At what point do you cross over from:
"Various ways to accomplish the same goal is good,
because it allows the language to work the way
different people think about working."
into the land of:
"Duplicate names and techniques to do the same
atomic thing ends up confusing the nubys"
?

results = my_array.collect{ ... }
results = my_array.map{ ... }

IMHO these were introduced to match other languages notations. I think it
makes life easier for newcomers.
a = Proc.new{ ... }
b = lambda{ ... }

Same here.
def whee; ...; end
c = self.method( :whee )

These are two completely different cups of tea.
def foo &blockAsBlock
blockAsBlock.call
yield
end

Same here: the &b notation converts the block into a proc making it possible
to store it somewhere or pass it on.
def bar blockAsParam
blockAsParam.call
end

I'd consider this a different case, too, because here the block can't be
handed over via "foo { ... }".
Regexp globals vs. MatchData
#insert your own examples here

*That* is an area where I definitely like to see improvements (see the
thread some time ago about String#scan and MatchData).

On the whole I feel pretty comfortable with the way Ruby does things
although I recognize a certain tendency to increase redundancy ("lambda" and
"proc" comes to mind). As far as I remember I wasn't confused when I was a
RubyNuby. But then again, everybody feels different about this.

Kind regards

robert
 
G

gabriele renzi

Gavin Kistner ha scritto:
#insert your own examples here

%{x}

%q{x}
%Q{x}
"x"
'x'
and heredocs.
Definitely too many ways for me :)
Amnyway I subscribe robert klemme's Ideas in the other response.
 
D

David A. Black

Hi --

IMHO these were introduced to match other languages notations. I think it
makes life easier for newcomers.

If only the things that make life easier for newcomers could disappear
later, like training wheels on a bicycle.... :) Personally I've
never minded the handful of duplicate method names, though I know some
people do.
Same here.

Proc.new and lambda aren't the same as each other, though:

irb(main):014:0> l = lambda {|a,b|}
=> #<Proc:0x00000000@(irb):14>
irb(main):015:0> pr = Proc.new {|a,b|}
=> #<Proc:0x00000000@(irb):15>
irb(main):016:0> l.call(1)
ArgumentError: wrong number of arguments (1 for 2)
from (irb):14
from (irb):14:in `call'
from (irb):16
irb(main):017:0> pr.call(1)
=> nil
These are two completely different cups of tea.

I think these two lines go together: Gavin was showing that a method,
like a block, lambda, or Proc, could be assigned to a variable.

I tend to feel that the [block, lambda, Proc, method] stuff is too
complicated. But I know Matz is working on it; hopefully there will
be some unification/simplification to come.


David
 
T

ts

D> I tend to feel that the [block, lambda, Proc, method] stuff is too
D> complicated.

I'm agree with you, just make it more complex to solve the
complication :)

svg% cat b.rb
#!/usr/bin/ruby
require 'aa'

class A < Proc
def self.new(&block)
proc(&block)
end
end

a = A.new {|x, *y| p x,y }
p a.class
a.call([1, 2])
svg%

svg% b.rb
A
[1, 2]
[]
svg%


Guy Decoux
 
G

Gavin Kistner

AFAIC, there's no objective answer.
[...]
If I were king, I'd tighten it up just a little, and probably screw
the whole thing up.

Yeah. I suppose the question was sort of rhetorical, my way of saying
"I raise my hand as someone who feels that there is too much
duplication, but then again, I'm not king, and I don't wish to be."
 
C

Chris Pine

 At what point do you cross over from: "Various ways to accomplish
 the same goal is good, because it allows the language to work the
 way different people think about working." into the land of:
 "Duplicate names and techniques to do the same atomic thing ends up
 confusing the nubys" ?

Simple: nubys should only be taught one way to do a thing. What's harder than learning to program? Learning to program twice. Or you could ask, I'm getting ready to teach someone two things about Ruby... shouldn't they be *different* things?

(This is something I really tried to follow in my tutorial, which even has a TMTOWTDI section near the end: http://pine.fm/LearnToProgram/)

So I think the cross over is really in the other direction: from nuby to TMTOWTDI.


 If only the things that make life easier for newcomers could
 disappear later, like training wheels on a bicycle.... :)

So naturally I completely disagree with this! :)

Duplicates do *not* make things any easier for newcomers. Learning something twice is just that much harder, and then having one of them disappear later would be disastrous. Again, I think it really moves in the other direction: from nuby to TMTOWTDI.

(Yes, if you are teaching Ruby to a functional programmer, you use map instead of collect (are those really the same? I just always avoided collect: wrong english word, I think), but you still teach them only *one* of them.)

First you learn one way to do it. (Depending on your background, lambda might make more sense than proc (nevermind that these *aren't* the same, though I'll never keep up with that).) Then, once you are doing a pretty good job of coding Ruby on your own, you learn a few other ways to do things so you can read other people's code (which is always a little trickier, anyway).

Just some thoughts,

Chris
 
G

Gavin Kistner

If only the things that make life easier for newcomers could disappear
later, like training wheels on a bicycle.... :)

I suppose that's my wish, too. As unrealistic as it may be.
("Sorry, play time is over. All your existing code may crash and burn,
but in the end it'll make you a better programmer.")

What I'd think was nice is if a bunch of things were officially
deprecated; no runtime warning (although perhaps with a -w or
something) but where exact duplicates exist, the King from on High
would say "thou shalt use #foo and not #bar". (I was even thinking of
removing the deprecated names from the documentation, but then that's
no good for someone needing to decipher existing code.)


Proc.new and lambda aren't the same as each other, though:

Whoa, that I didn't know.
So a lambda is more like a method (currently)?

Actually, I'd say this is an argument for merging, or something. My
personal principle of least surprise was violated when I found that I
couldn't create a block with default parameters. Procs, blocks,
methods, lambdas ... four ways to do almost exactly the same thing.



I'm not sure if I'm a nuby or not; I certainly am when it comes to
grokking lambdas. The concepts are all pretty clear (not confusing when
learning), but when I was designing the EventTarget module, I kept
waffling between:
def add_event_listener( evt_type, callback_proc )
and
def add_event_listener( evt_type, &callback_proc )

Proc-as-param allows multiple params to be procs, and makes it easy to
pass methods/procs/lambdas (which are what would most likely be used
for a callback: an existing, centrally-defined procedure)...but
prevents blocks from being used without Proc.new. That's bad, because
Ruby people LIKE blocks. I know I do.

Proc-as-block allows no more than one 'proc', and requires &foo to be
used when passing method references or procs or lambdas..but *does*
allow blocks.

I suppose this is a case where subtle flexibility is important
(different functionality), but it's the case of the blank canvas
scaring and stymying the novice artist: "Where do I begin?" There's so
much/too much flexibility; so much overlap muddled in with the
tradeoffs it's frustrating. But now I'm getting onto the specific topic
of merging the features and fun of both sides, instead of the general
"I'd like to see a little less duplication in the future, please"
topic.
 
G

Gavin Kistner

(Yes, if you are teaching Ruby to a functional programmer, you use map
instead of collect (are those really the same? I just always avoided
collect: wrong english word, I think), but you still teach them only
*one* of them.)

Funny, I never understood what #map did. People used it all the time
and it baffled me. I kept saying "I should learn this method, because
people keep showing how to use it for powerful, terse solutions,
but...I'm baffled."

Then someone showed me the #collect method, and I fell in love. It's
awesome. I extended arrays in Javascript to use it, I love it so much.

...it was a week later than I pulled up the documentation and saw that
they're the same thing. Something about 'map' made absolutely no sense
to me (it implies a hash-like permanent connection between the old and
the new), and collect made perfect sense (go traipsing through the
entire field of daisies, picking up only the best ones).

So if we were deprecating duplicates, I vote to get rid of #map.
(This is the part where 100 rubyists say "No! #collect sucks, #map is
king!" and my entire argument for less duplication is shot down by the
fact that people like different things.)
 
Z

Zach Dennis

I have been thinking lately about rangess and I will give you the two
different range operators and what comes to mind first.

Operator One: .. (two dots)
Example: 1..5
What comes to mind: Exclusive
How It Works: Inclusive (the last number 5, is included)

Operator Two: ... (three dots)
Example: 1...5
What comes to mind: Inclusive
How It Works: Exclusive (the last number 5, is excluded)

How range operators work seems sort of backwards to me. It would appear
as if the "..." (three dots) would be the inclusive one, including the
last value and the ".." (two dots) would be exclusive and exclude the
last value.

Am I off in my own little world here or have others pondered this?
(Perhaps it has been brought up before?) I am not requesting a change on
this, I am merely pointing out what seems unnatural in a very natural
language.

Zach
 
B

Brian Schröder

Zach said:
I have been thinking lately about rangess and I will give you the two
different range operators and what comes to mind first.

Operator One: .. (two dots)
Example: 1..5
What comes to mind: Exclusive
How It Works: Inclusive (the last number 5, is included)

Operator Two: ... (three dots)
Example: 1...5
What comes to mind: Inclusive
How It Works: Exclusive (the last number 5, is excluded)

How range operators work seems sort of backwards to me. It would appear
as if the "..." (three dots) would be the inclusive one, including the
last value and the ".." (two dots) would be exclusive and exclude the
last value.

Am I off in my own little world here or have others pondered this?
(Perhaps it has been brought up before?) I am not requesting a change on
this, I am merely pointing out what seems unnatural in a very natural
language.

Zach
Hello Zach,

very good point you make. I imagine that the inclusive version is used
more often, so someone thought, lets save a point here.

But I have to admit I just learned it and never questioned it. Thats a
bad thing ;)

Regards,

Brian
 
R

Robert Klemme

Zach Dennis said:
I have been thinking lately about rangess and I will give you the two
different range operators and what comes to mind first.

Operator One: .. (two dots)
Example: 1..5
What comes to mind: Exclusive
How It Works: Inclusive (the last number 5, is included)

Operator Two: ... (three dots)
Example: 1...5
What comes to mind: Inclusive
How It Works: Exclusive (the last number 5, is excluded)

How range operators work seems sort of backwards to me. It would appear
as if the "..." (three dots) would be the inclusive one, including the
last value and the ".." (two dots) would be exclusive and exclude the
last value.

Am I off in my own little world here or have others pondered this?
(Perhaps it has been brought up before?) I am not requesting a change on
this, I am merely pointing out what seems unnatural in a very natural
language.

I never thought about this but it seems you are right. (Sometimes it
seems better to not think about everything :)

robert
 
A

Austin Ziegler

How range operators work seems sort of backwards to me. It would appear
as if the "..." (three dots) would be the inclusive one, including the
last value and the ".." (two dots) would be exclusive and exclude the
last value.

Am I off in my own little world here or have others pondered this?
(Perhaps it has been brought up before?) I am not requesting a change on
this, I am merely pointing out what seems unnatural in a very natural
language.

It's the distinction between
0..5 == [0, 5] # mathematical notation
and
0...5 == [0, 5) # mathematical notation

In part, this is something that Ruby inherits -- I *think* -- from
Perl, which uses the .. and ... in this way.

-austin
 
A

Andrew Johnson

the new), and collect made perfect sense (go traipsing through the
entire field of daisies, picking up only the best ones).

Perfect sense? Your description sounds a lot more like #select than
#collect :)

andrew
 
P

Peter Hickman

Programming languages are a lot like philosophy. Nothing ever gets
thrown away!

I find the duplicate names for a method a, minor, irritant but getting
rid of them is not going to be painless.
 
G

Gavin Kistner

How range operators work seems sort of backwards to me. It would
appear as if the "..." (three dots) would be the inclusive one,
including the last value and the ".." (two dots) would be exclusive
and exclude the last value.

I was thinking this exact same thing in the shower yesterday morning.


I've tried to memorize what _why said about them, to remember:
Think of it as an accordion which has been squeezed down for carrying.
(Sure, you can build a great sense of self-worth by carrying around an
unfolded accordion, but sometimes a person needs to wallow in
self-doubt, carefully concealing the squeeze-box.) The parentheses are
the handles on the sides of a smaller, handheld accordion. The dots
are the chain, keeping the folds tightly closed.

Normally, only two dots are used. If a third dot is used, the last
value in the range is excluded.

(0...5) represents the numbers 0 through 4.

When you see that third dot, imagine opening the accordion slightly.
Just enough to let one note from its chamber. The note is that end
value. We’ll let the sky eat it.

Source: http://poignantguide.net/ruby/chapter-3.html#section2
 
H

Henrik Horneber

Hi!

From an intellectual point I sort of understand the '..' and '..'
notation. What distracts me most, is the visual difference ... that the
visually longer three dot form contains fewer elements than the shorter
two dot form.

(1..5).to_a
=>[1,2,3,4,5]
(1...5).to_a
=>[1,2,3,4]

Henrik
 
A

Austin Ziegler

From an intellectual point I sort of understand the '..' and '..'
notation. What distracts me most, is the visual difference ... that the
visually longer three dot form contains fewer elements than the shorter
two dot form.

(1..5).to_a
=>[1,2,3,4,5]
(1...5).to_a
=>[1,2,3,4]

That's a dangerous consideration -- and not always true:

irb(main):001:0> (1..5).include?(4.99)
=> true
irb(main):002:0> (1...5).include?(4.99)
=> true
irb(main):003:0>

1...5 doesn't include only the numbers 1, 2, 3, and 4 -- it contains
the infinities between the numbers, and the infinity between 4 and 5,
but not 5 itself.

-austin
 
H

Henrik Horneber

Austin said:
From an intellectual point I sort of understand the '..' and '..'
notation. What distracts me most, is the visual difference ... that the
visually longer three dot form contains fewer elements than the shorter
two dot form.

(1..5).to_a
=>[1,2,3,4,5]
(1...5).to_a
=>[1,2,3,4]


That's a dangerous consideration -- and not always true:

irb(main):001:0> (1..5).include?(4.99)
=> true
irb(main):002:0> (1...5).include?(4.99)
=> true
irb(main):003:0>

1...5 doesn't include only the numbers 1, 2, 3, and 4 -- it contains
the infinities between the numbers, and the infinity between 4 and 5,
but not 5 itself.

-austin

Still, it's the 'larger' Range.
Otherwise, good point, thx.
 

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

Staff online

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top