Yet Another useless Ruby 2 Idea

J

Jonas Hartmann

mathew said:
Consider the following code:

def bar
puts "ONE"

def foo
puts "TWO"

def bar
puts "THREE"
end

bar
foo

What does it print?

Answer #1:

def bar
puts "ONE"
end

def foo
puts "TWO"
end

def bar
puts "THREE"
end

bar
foo

prints

THREE
TWO

Answer #2:

def bar
puts "ONE"
end

def foo
puts "TWO"

def bar
puts "THREE"
end
end

bar
foo

prints

ONE
TWO

So I don't think it's unambiguous at all.

shouldnt it puts "one" "three" "two"?
 
D

Daniel Brockman

mathew said:
Python has a special -t option just to help debug the
problems that structurally significant indentation causes

-t Issue a warning when a source file mixes tabs and
spaces for indentation in a way that makes it depend
on the worth of a tab expressed in spaces.

That problem is caused by people using physical tabs.

Just ban tabs altogether. Problem solved.
 
G

gabriele renzi

mathew ha scritto:
Consider the following code:
So I don't think it's unambiguous at all.

it is, I wrote that method nesting should be prohibited, thus your
second interpretation is invalid and thus there is no ambiguity.

Nested method definitions are mostly useless anyway because of the
method scoping (actually, I think I never saw an example of using a
nested def instead of a define_method in some years of rubying :)

But mind you: I'm not really advocating this thing, it has already
proven non-obvious 3 or 4 times as of now, and thus it is a Bad Idea(TM)
 
B

Ben Giddings

Yeah, I figured that out right after I had posted my message...

But still, you can see that the python syntax is quite a bit more
readable ( at least in this case ).

I completely disagree. "item for item in items if item"? How is
that easy to understand?

The Ruby way may involve a few more keystrokes, but it's much more
clear what's happening.

items.select {|item| item > 2 }.map {|item| item * 2 }

First you use "select", giving you an array, then you map the
elements of the array to another. The temporary variables you create
are obvious, unlike the Python example where you start using the
variable even before you declare it, and the two tasks (selecting
certain elements of the array, and manipulating those elements) are
cleanly separated. To me, I can't tell if the "if item > 2" happens
each time, or only once.

I think it's like lisp. Once you get used to it, you can read it an
parse it efficiently, but getting there is a real pain, and until
your brain is used to those constructs it isn't at all intuitive.

Ben
 
B

Ben Giddings

Uh, this is much less of a problem with indentation-based
syntax than with delimiter-based such.

def foozer(x)
if x > 10
print x
end
do other stuff
end

Comment out the `if' line in the above code and you still
get a syntax error, but on a different line!

Right, because you need to comment out both sides of the
conditional. That's not too difficult. Compare it to python

def helloworld(debug):
if (debug):
print("starting engines\n")
print("main screen turn on\n")
print("You have no chance to survive make your time\n")
print("Hello World!\n")

If I want that bit of text to appear every time I run the program, I
not only have to comment out the "if (debug):" line, but also fix the
indentation on all the lines in that conditional.

Ben
 
J

Jos Backus

On Thu, Aug 11, 2005 at 01:00:12AM +0900, Ben Giddings wrote:
[snip]
Compare it to python

def helloworld(debug):
if (debug):

if (1 or debug):
print("starting engines\n")
print("main screen turn on\n")
print("You have no chance to survive make your time\n")
print("Hello World!\n")

If I want that bit of text to appear every time I run the program, I
not only have to comment out the "if (debug):" line, but also fix the
indentation on all the lines in that conditional.

Not necessarily. See above.
 
J

Jacob Fugal

=20
I completely disagree. "item for item in items if item"? How is
that easy to understand?

Ummm, maybe a closer translation would be:

"computation for item in collection if condition"

Naming computation/item/collection/condition the same and then
declaring unreadability is a straw man.

Given the translation above, consider the following english comment of
what is actually happening:

"do computation for each item in collection with condition"

The "do" and "each" are implicit. That's fine with me, the language
shouldn't read as full english or it will be too verbose. The only
other change is replacing "if" by "with". It be nice if the list
comprehension used "with" instead:

manager_salaries =3D [e.salary for e in employees with e.manager?]
vs.
manager_salaries =3D [e.salary for e in employees if e.manager?]

Depends on who you are. Me? I like "with" better, but can live with
"if" just fine. I think the main readability argument for list
comprehensions is that the flow of the construct is similar to the
flow of the english sentence that describes it. Ok, is a
select/collect implementation less readable?

manager_salaries =3D employees.
select{ |e| e.manager? }.
collect{ |e| e.salary }

English translation:

"For each item in collection with condition, do computation"

NO! An argument for readability of list comprehensions is not an
argument against readability of select/each/collect etc. I love thems,
and I want to keep thems! :) Adding list comprehensions wouldn't imply
removal of the equally readable and powerful block constructs we're
used to.

However, notice one thing about the select/collect implementation
above. We iterate through employees once and create a temporary array.
We then iterate through that temporary array again during the collect.
That seems a bit inefficient to me. The list comprehension -- with
equal readability -- removes that inefficiency.

Does Ruby need list comprehensions to solve that? Not necessarily:

module Enumerable
def collect_filtered(filter: filter, mapping: mapping)
self.inject([]) { |c,e| filter[e] ? c << mapping[e] : c }
end
end

manager_salaries =3D employees.collect_filtered(
filter: -> (e) { e.manager? },
mapping: -> (e) { e.salary }
)

I've opted to use the proposed 2.0 syntax for lambdas for consistency
with the assumption of named parameters. This would be much less
readable without the named parameters. This solves the efficiency
problem, but does it really retain the readability of either the
inefficient select/collect implementation or the list comprehension?
I, personally, don't think so.

I hope you've enjoyed this little detour through my thought process...

Jacob Fugal
 
T

ts

m> No--the second definition of bar is only in scope within foo, so when
m> bar is called, the only visible definition is the first one, which
m> prints "ONE". Then foo is called, which prints "TWO". I tested my
m> examples before posting :)

Change the order to

foo
bar

and look the result



Guy Decoux
 
D

David A. Black

Hi --

Well, I disagree with prohibiting nested methods.


What do you mean? When I try it, a nested method is scoped so that it is
only visible inside the method it's defined in. That's exactly the behavior
you want for nested methods to be useful.

$ ruby -ve 'def x; def y; 1; end; end; x; p y'
ruby 1.8.2 (2004-12-25) [i686-linux]
1


David
 
G

gabriele renzi

mathew ha scritto:
No--the second definition of bar is only in scope within foo, so when
bar is called, the only visible definition is the first one, which
prints "ONE". Then foo is called, which prints "TWO". I tested my
examples before posting :)

actually, not, #bar just gets redefined overriding the former definition.

There are no nested method in ruby (yet):

irb(main):001:0> def bar
irb(main):002:1> puts "ONE"
irb(main):003:1> end
=> nil
irb(main):004:0>
irb(main):005:0* def foo
irb(main):006:1> puts "TWO"
irb(main):007:1>
irb(main):008:1* def bar
irb(main):009:2> puts "THREE"
irb(main):010:2> end
irb(main):011:1> end
=> nil
irb(main):012:0>
irb(main):013:0* bar
ONE
=> nil
irb(main):014:0> foo
TWO
=> nil
irb(main):015:0> bar
THREE
=> nil
 
R

rm_rails

In the Programming Ruby book in the section of namespaces, I see
the example:

require "trig"
require "action"
y = Trig.sin(Trig::pI/4)
wrongdoing = Action.sin(Action::VERY_BAD)

It seems very common to me to use constants from the module
as parameters to the module - and rather uncommon to want
constants from a different module as a parameer.

Is there a reason why a method's arguments can't automatically
include the namespace of the module the method came from so
I could simply write:

y = Trig.sin(PI/4)
wrongdoing = Action.sin(VERY_BAD)

and have it automatically look in the Trig namespace for
the first PI and the Action namespace for VERY_BAD?
I think this would make a lot of code that makes heavy use
of constants look a lot cleaner; and perhaps encourage people
to use constants more often rather than just magic numbers
or strings or symbols as arguments.
 
A

Austin Ziegler

In the Programming Ruby book in the section of namespaces, I see the
example:
=20
require "trig"
require "action"
y =3D Trig.sin(Trig::pI/4)
wrongdoing =3D Action.sin(Action::VERY_BAD)
It seems very common to me to use constants from the module as
parameters to the module - and rather uncommon to want constants from
a different module as a parameer.
Is there a reason why a method's arguments can't automatically include
the namespace of the module the method came from so I could simply
write:
=20
y =3D Trig.sin(PI/4)
wrongdoing =3D Action.sin(VERY_BAD)
=20
and have it automatically look in the Trig namespace for the first PI
and the Action namespace for VERY_BAD? I think this would make a lot
of code that makes heavy use of constants look a lot cleaner; and
perhaps encourage people to use constants more often rather than just
magic numbers or strings or symbols as arguments.

Um.

1. Symbols aren't "magic"; they're effectively constants.
2. What if I have:

require 'action'

module VERY_BAD
Action.sin(VERY_BAD)
end

Obviously, this is, itself VERY_BAD if Action.sin does
Action.sin Action::VERY_BAD
instead of using ::VERY_BAD which is, in this case, self. Why? Because
it means that if I *meant* to pass in ::VERY_BAD, I have to explicitly
specify it rather than relying on Ruby's constant lookup rules.

If Action is a *module*, then you have more flexibility:

module Action
def self.sin(my_sin)
p my_sin
end
VERY_BAD =3D "I'm just drawn that way."
end
=20
module VERY_BAD
Action.sin(VERY_BAD) # =3D> VERY_BAD
end

module VERY_BAD
include Action
Action.sin(VERY_BAD) # =3D> "I'm just drawn that way."
end

It's probably better to leave this alone.

-austin
--=20
Austin Ziegler * (e-mail address removed)
* Alternate: (e-mail address removed)
 
X

Xeno Campanoli

There are just too many problems that can quickly be solved by
multi-dimensional arrays and hashes not to have them and have them
easily. I used the hack from "matz" today to make a 2d hash, and it's
ugly and unworthy of Ruby. You should be able to do this without any
extra steps just like in Perl. If the project ends up getting bigger
THEN you refactor it, but YOU JUST GOT TO HAVE THAT.

Sorry. This is of course with all respect to everyone out there.
 
B

Bill Kelly

From: "Xeno Campanoli said:
There are just too many problems that can quickly be solved by
multi-dimensional arrays and hashes not to have them and have them
easily. I used the hack from "matz" today to make a 2d hash, and it's
ugly and unworthy of Ruby. You should be able to do this without any
extra steps just like in Perl. If the project ends up getting bigger
THEN you refactor it, but YOU JUST GOT TO HAVE THAT.

I don't know how to do it with Array, because Array doesn't
seem to accept a block for its default value generation like
Hash does.

But with Hash:

hoh = lambda { Hash.new {|h,k| h[k] = hoh.call} }
x = hoh.call # create autovivifying hash-of-hashes => {}
x[1][2][3][4][5] = "spleen" => "spleen"
x
=> {1=>{2=>{3=>{4=>{5=>"spleen"}}}}}


Regards,

Bill
 
B

Brian Schröder

From: "Xeno Campanoli said:
There are just too many problems that can quickly be solved by
multi-dimensional arrays and hashes not to have them and have them
easily. I used the hack from "matz" today to make a 2d hash, and it's
ugly and unworthy of Ruby. You should be able to do this without any
extra steps just like in Perl. If the project ends up getting bigger
THEN you refactor it, but YOU JUST GOT TO HAVE THAT.
=20
I don't know how to do it with Array, because Array doesn't
seem to accept a block for its default value generation like
Hash does.
=20
But with Hash:
=20
hoh =3D lambda { Hash.new {|h,k| h[k] =3D hoh.call} }
=20
x =3D hoh.call # create autovivifying hash-of-hashes =3D> {}
x[1][2][3][4][5] =3D "spleen" =3D> "spleen"
x
=3D> {1=3D>{2=3D>{3=3D>{4=3D>{5=3D>"spleen"}}}}}
=20
=20
Regards,
=20
Bill

Though I never had use for this, here is my attempt on an
autovivifying array of arrays:

class Autoarray < Array
def initialize(size=3D0, default=3Dnil, update =3D nil, update_index =3D =
nil)
super(size, default)
@update, @update_index =3D update, update_index
end
=20
def [](k)
if k.abs() < self.length
super(k)
else
Autoarray.new(0, nil, self, k)
end
end

def []=3D(k, v)
@update[@update_index] =3D self if @update and @update_index
super
end
end

a =3D Autoarray.new
a[1][2][3] =3D 12
a #=3D> [nil, [nil, nil, [nil, nil, nil, 12]]]
a[2][3][4] #=3D> []
a #=3D> [nil, [nil, nil, [nil, nil, nil, 12]]]

regards,

Brian

--=20
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/
 
P

Pit Capitain

Brian said:
Though I never had use for this, here is my attempt on an
autovivifying array of arrays:
=20
class Autoarray < Array
def initialize(size=3D0, default=3Dnil, update =3D nil, update_index = =3D nil)
super(size, default)
@update, @update_index =3D update, update_index
end
=20
def [](k)
if k.abs() < self.length
super(k)
else
Autoarray.new(0, nil, self, k)
end
end
=20
def []=3D(k, v)
@update[@update_index] =3D self if @update and @update_index
super
end
end
=20
a =3D Autoarray.new
a[1][2][3] =3D 12
a #=3D> [nil, [nil, nil, [nil, nil, nil, 12]]]
a[2][3][4] #=3D> []
a #=3D> [nil, [nil, nil, [nil, nil, nil, 12]]]

Very nice. There are problems with negative indexes (try a[1][-2][2])=20
but I'm sure they can be fixed. I really like the idea.

Regards,
Pit
 
R

Robert Klemme

Pit said:
Brian said:
Though I never had use for this, here is my attempt on an
autovivifying array of arrays:

class Autoarray < Array
def initialize(size=0, default=nil, update = nil, update_index =
nil) super(size, default)
@update, @update_index = update, update_index
end

def [](k)
if k.abs() < self.length
super(k)
else
Autoarray.new(0, nil, self, k)
end
end

def []=(k, v)
@update[@update_index] = self if @update and @update_index
super
end
end

a = Autoarray.new
a[1][2][3] = 12
a #=> [nil, [nil, nil, [nil, nil, nil, 12]]]
a[2][3][4] #=> []
a #=> [nil, [nil, nil, [nil, nil, nil, 12]]]

Very nice. There are problems with negative indexes (try a[1][-2][2])
but I'm sure they can be fixed. I really like the idea.

While reading this thread I thought class Matrix would be a good solution,
but it lacks these properties:

- factory method that takes dimension sizes instead of actual elements

- capability to handle more than two dimensions

- autovivification

How do people think about extending class Matrix of the std lib with these
properties? We could then have Matrix[3,4,5,10,2] which creates a five
dimensional 3x4x5x10x2 Matrix etc. Note that this factory method does not
conflict with the old usage Matrix[[1,2],[3,4]] where arrays were used to
provide actual values.

Kind regards

robert
 
B

Brian Schröder

Brian said:
Though I never had use for this, here is my attempt on an
autovivifying array of arrays:

[snip old code]

Very nice. There are problems with negative indexes (try a[1][-2][2])
but I'm sure they can be fixed. I really like the idea.
=20
Regards,
Pit
=20
=20

Should have written unit tests, but it is just a hack. Heres the
correction, so no correctness guarantee yet.

class Autoarray < Array
def initialize(size=3D0, default=3Dnil, update =3D nil, update_index =3D =
nil)
super(size, default)
@update, @update_index =3D update, update_index
end
=20
def [](k)
if -self.length+1 < k and k < self.length
super(k)
else
Autoarray.new(0, nil, self, k)
end
end

def []=3D(k, v)
@update[@update_index] =3D self if @update and @update_index
super
end
end

a =3D Autoarray.new
a[1][2][3] =3D 12
a #=3D> [nil, [nil, nil, [nil, nil, nil, 12]]]
a[2][3][4] #=3D> []
a #=3D> [nil, [nil, nil, [nil, nil, nil, 12]]]
a[1][-2][1] =3D "Negative"
a #=3D> [nil, [nil, [nil, "Negative"], [nil, nil, nil, 12]]]

regards,

Brian

--=20
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/
 
A

Ara.T.Howard

Xeno said:
There are just too many problems that can quickly be solved by
multi-dimensional arrays and hashes not to have them and have them easily.
I used the hack from "matz" today to make a 2d hash, and it's ugly and
unworthy of Ruby. You should be able to do this without any extra steps
just like in Perl. If the project ends up getting bigger THEN you refactor
it, but YOU JUST GOT TO HAVE THAT.

Well, the support for multiple dimensions of index selector is already there.
That is, you already have a[a][c][d][e][f][g][h]..., you just need to
create the array to start with. For that part, it's not too hard to write a
convenient multi-dimensional array factory method:

require 'pp'

def ArrayFactory(dimensions, initialvalue)
size = dimensions.first
if dimensions.length == 1
return Array.new(size, initialvalue)
else
rest = dimensions[1,dimensions.length-1]
a = Array.new(size)
for i in 0..size
a = ArrayFactory(rest, initialvalue)
end
return a
end
end

a = ArrayFactory([3, 5, 7], "Hi!")
pp a

a[2][3][7] = "Hello!"
puts a[2][3][7]
pp a[2][3]

I have to say, though, that I've never had much need for multi-dimensional
arrays. Outside the realm of scientific data analysis, most of the time you
really want hashes because your "array" is sparse, has unusual bounds, or
whatever. At that point you should probably be looking at writing a proper
storage class.


or use narray:

harp:~ > cat a.rb
require 'narray'

na = NArray::byte 42, 42, 42

p na.size
p na.shape

na[] = 42
p na.min
p na.max
p na.mean.ceil

na[] = 0
na[0 ... (na.size/2)] = 84
p na.min
p na.max
p na.mean.ceil



harp:~ > time ruby a.rb
74088
[42, 42, 42]
42
42
42
0
84
42

real 0m0.020s
user 0m0.020s
sys 0m0.000s


__fast__

-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| Your life dwells amoung the causes of death
| Like a lamp standing in a strong breeze. --Nagarjuna
===============================================================================
 
X

Xeno Campanoli

--------------080209010304040603030602
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Bill said:
There are just too many problems that can quickly be solved by
multi-dimensional arrays and hashes not to have them and have them
easily. I used the hack from "matz" today to make a 2d hash, and it's
ugly and unworthy of Ruby. You should be able to do this without any
extra steps just like in Perl. If the project ends up getting bigger
THEN you refactor it, but YOU JUST GOT TO HAVE THAT.

I don't know how to do it with Array, because Array doesn't
seem to accept a block for its default value generation like
Hash does.

But with Hash:

hoh = lambda { Hash.new {|h,k| h[k] = hoh.call} }
Thank you. I used this just yesterday, and it helped a lot with a
report reorganization I wanted to do.

The first time I used Perl for a web report (Perl IV I think) I believe
it didn't have multi-dimensional hashes either. Once I got Perl5, I
could do a lot more much more easily and still clearly. I agree with
what the one fellow said that I don't use multi-dimensional arrays
nearly as much as multi-dimensional hashes, but for instance it would be
nice to have as a memory item on a multi-dimensional hash read.

I know in the long run it's better to use more formal constructs for a
lot of things in order to make a program clear and maintainable, but
really n>2 arrays and hashes are really the thing I love most about
Perl, and I think it allows you to do organizations that aid
understanding in very important ways with reports that can be written ad
hoc very quickly. These are kinds of things that, from my experience,
really leverage strong management of things, but are over the head of
many people in the world (but presumably never a Ruby programmer). Most
people don't make busy, thick reports because the object is to impress
the boss, not to leverage your best users, but I'm lucky at getting work
situations where I can do the latter and not worry as much about the
former. Uh oh, I'm bragging. Avert!

I'm tempted to post some of yesterdays code, but it's for Real Networks,
and it's probably more appropriate not to pass it around. Oh, I guess
that means I'm doing a real project with Ruby by the way. Thanks for
the help. Go Ruby!
=> {}

x[1][2][3][4][5] = "spleen"
=> "spleen"

=> {1=>{2=>{3=>{4=>{5=>"spleen"}}}}}


Regards,

Bill


--
Xeno Campanoli, (e-mail address removed), http://www.eskimo.com/~xeno
The Internet: I'd rather have Al invent it than have George take it over.


--------------080209010304040603030602--
 

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

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,123
Latest member
Layne6498
Top