Any solutions to Ruby's inconsistencies?

Ruby has definite positives over Java and even other scripting
languages, but many negatives too. One negative is the inconsistency of
how rules seem to be applied in the language and accompanying toolsets.
Here are a few that have bitten me:

1. I almost immediately got started with Ruby on Rails and loved the
idea of partials, but then I found that the ||= idiom doesn't work on
partials' parameters.

<% my_param_a ||= 1 # Errors out
    my_param_a = my_param_a ? my_param_a : 1 # works
-%>

That seemed odd as I thought both were equivalent, and it broke some of
the trust I had for Ruby. Not as much as early Rails' use of 2 separate
variables for RAILS_ENV, but...

2. Then when using blocks to process an array I tried to use another
Ruby control structure:

  arr=[1,2,3,4]
  arr2 = arr.collect{|ii| return 0 if ii == 3; ii+1}
  # result: LocalJumpError: unexpected return

That also caught me off guard - I need the block to return a value, to
evaluate to a value - but suddenly I'm told that 'return' doesn't mean
what I think it means? At least not inside a block (or Proc.new)...

3. Originally I was taught that symbols were the salvation of memory and
key problems - and they certainly sounded like it. Up until the point a
few days later when one (Rails?) map used Symbols and another used
Strings. Ouch.
    Without any explicit typing abilities in the language (optional or
otherwise?) it seems like the only solution is to return to basic string
matches:
    regex = Regexp.compile("^#{matcher.to_s}$", Regexp::IGNORECASE)
    key = map.keys.find{ |key| key.to_s =~ regex }
Yuck.

4. And what's up with Ruby incorrectly naming their Map 'Hash'? Or is
my C.S. idea of a Hash too limited? Granted in Java they have HashMap,
but if you enter one value and get a second one out it is a Map,
regardless of how the keys are stored. A 'Hash' would instead be a type
of set.

Please let me know how I can supplement my possibly deficient Ruby
education :slight_smile: Relevant discussions or sections of "The Ruby Way"
appreciated!

-Chris

···

--
Posted via http://www.ruby-forum.com/.

C. Dagnon wrote:

Ruby has definite positives over Java and even other scripting
languages, but many negatives too. One negative is the inconsistency
of how rules seem to be applied in the language and accompanying
toolsets. Here are a few that have bitten me:

1. I almost immediately got started with Ruby on Rails and loved the
idea of partials, but then I found that the ||= idiom doesn't work on
partials' parameters.

<% my_param_a ||= 1 # Errors out
    my_param_a = my_param_a ? my_param_a : 1 # works
-%>

That seemed odd as I thought both were equivalent, and it broke some
of the trust I had for Ruby.

Rails isn't Ruby. If I wrote a program in Ruby that erased every file
on your hard-drive, would you blame Ruby or me?

                              Not as much as early Rails' use of 2
separate variables for RAILS_ENV, but...

2. Then when using blocks to process an array I tried to use another
Ruby control structure:

  arr=[1,2,3,4]
  arr2 = arr.collect{|ii| return 0 if ii == 3; ii+1}

This makes no sense. Correct:

[1,2,3,4].map{|n| if 3==n; 0 else n+1 end}
    ==>[2, 3, 0, 5]
[1,2,3,4].map{|n| 3==n ? 0 : n+1 }
    ==>[2, 3, 0, 5]

  # result: LocalJumpError: unexpected return

That also caught me off guard - I need the block to return a value, to
evaluate to a value - but suddenly I'm told that 'return' doesn't mean
what I think it means? At least not inside a block (or Proc.new)...

3. Originally I was taught that symbols were the salvation of memory
and key problems - and they certainly sounded like it. Up until the
point a few days later when one (Rails?)

Rails is not Ruby. Rails could be be the worst piece of crap in the
universe and it still wouldn't be Ruby's fault.

                         map used Symbols and another
used Strings. Ouch.
    Without any explicit typing abilities in the language (optional or
otherwise?) it seems like the only solution is to return to basic
string matches:
    regex = Regexp.compile("^#{matcher.to_s}$", Regexp::IGNORECASE)

Horrible.

sym = :foo
    ==>:foo
"can FOO be found?"[ / #{ sym } /i ]
    ==>" FOO "

    key = map.keys.find{ |key| key.to_s =~ regex }
Yuck.

4. And what's up with Ruby incorrectly naming their Map 'Hash'?

You beg the question. You must be very ignorant of "scripting"
languages. Hash is short for Hash Table, what is called in Awk
an associative array.

                           Or is
my C.S. idea of a Hash too limited? Granted in Java they have
HashMap, but if you enter one value and get a second one out it is a
Map, regardless of how the keys are stored. A 'Hash' would instead
be a type of set.

A hash is a number returned by a hash function. An item's hash is
used to determine in which bucket of the hash-table it is put.

···

Please let me know how I can supplement my possibly deficient Ruby
education :slight_smile: Relevant discussions or sections of "The Ruby Way"
appreciated!

3. Originally I was taught that symbols were the salvation of memory and
key problems - and they certainly sounded like it. Up until the point a
few days later when one (Rails?) map used Symbols and another used
Strings. Ouch.
Without any explicit typing abilities in the language (optional or
otherwise?) it seems like the only solution is to return to basic string
matches:
regex = Regexp.compile("^#{matcher.to_s}$", Regexp::IGNORECASE)
key = map.keys.find{ |key| key.to_s =~ regex }
Yuck.

There's been endless discussion and confusion about Symbols, Strings,
what they mean, what they should be used for, and their relation to
each other. Rails did not help with HashWithIndifferentAccess, though
I imagine they thought they would. But I don't want to start anything
like that up. I just want to point out that a lot of that code is
unnecessary and could just be:

    key = map.keys.detect { |k| k.to_s.downcase ==
matcher.to_s.downcase }

Specifically, "#{something.to_s}" is not required because string
interpolation calls to_s on the object. And anyway, this example seems
confused with Symbol vs. String as well as case-insensitive matching.
If you want something like that, you write your own Hash (or Map)
subclass or find something someone else wrote. Maybe there's
HashWithReallyIndifferentAccess or HashThatJustKnowsWhatYouMean or
HashThatWillGiveYouTheValueOfSomeTangentionallyRelatedKey.

4. And what's up with Ruby incorrectly naming their Map 'Hash'?

This isn't only a Ruby thing. I'm used to it, but then again I came to
Ruby from Perl.

At least they're not called "dictionaries", right? Am I right?

Or is my C.S. idea of a Hash too limited? Granted in Java they
have HashMap, but if you enter one value and get a second one
out it is a Map, regardless of how the keys are stored.

Hey, why aren't Arrays called Maps instead?

···

On Mar 4, 10:02 am, "C. Dagnon" <c-soc-rubyfo...@dagnon.net> wrote:

--
-yossef

Ruby has definite positives over Java and even other scripting
languages, but many negatives too. One negative is the inconsistency of
how rules seem to be applied in the language and accompanying toolsets.
Here are a few that have bitten me:

1. I almost immediately got started with Ruby on Rails and loved the
idea of partials, but then I found that the ||= idiom doesn't work on
partials' parameters.

<% my_param_a ||= 1 # Errors out
   my_param_a = my_param_a ? my_param_a : 1 # works
-%>

That seemed odd as I thought both were equivalent, and it broke some of
the trust I had for Ruby. Not as much as early Rails' use of 2 separate
variables for RAILS_ENV, but...

What was the exact error? I don't know how ERB in Rails work, but sometimes those constructs are method calls and not variables.

2. Then when using blocks to process an array I tried to use another
Ruby control structure:

arr=[1,2,3,4]
arr2 = arr.collect{|ii| return 0 if ii == 3; ii+1}
# result: LocalJumpError: unexpected return

That also caught me off guard - I need the block to return a value, to
evaluate to a value - but suddenly I'm told that 'return' doesn't mean
what I think it means? At least not inside a block (or Proc.new)...

"return" in Ruby has a lexical meaning and can jump to the end of a scope (the end of the method). In some contexts, that is not allowed. Especially in the case of collect, that has to return an array that is as large as the first one.

It is not inconsistent: it is just not Javas return. So the language is right to tell you that it is not what you think it means: because it ain't.
Don't use it unless you really want to jump.

I for my part find Ruby a rather consistent language. It's just that the ruleset is not simple.

Regards,
Florian

···

On Mar 4, 2009, at 5:02 PM, C. Dagnon wrote:

--
Florian Gilcher

smtp: flo@andersground.net
jabber: Skade@jabber.ccc.de
gpg: 533148E2

Ruby has definite positives over Java and even other scripting
languages, but many negatives too. One negative is the inconsistency of
how rules seem to be applied in the language and accompanying toolsets.
Here are a few that have bitten me:

1. I almost immediately got started with Ruby on Rails and loved the
idea of partials, but then I found that the ||= idiom doesn't work on
partials' parameters.

<% my_param_a ||= 1 # Errors out
    my_param_a = my_param_a ? my_param_a : 1 # works
-%>

That seemed odd as I thought both were equivalent, and it broke some of
the trust I had for Ruby. Not as much as early Rails' use of 2 separate
variables for RAILS_ENV, but...

I don't use rails, and I don't know what a partial is, so I can't answer.
You probably better ask on a Rails list.

2. Then when using blocks to process an array I tried to use another
Ruby control structure:

  arr=[1,2,3,4]
  arr2 = arr.collect{|ii| return 0 if ii == 3; ii+1} # result:
  LocalJumpError: unexpected return

That also caught me off guard - I need the block to return a value, to
evaluate to a value - but suddenly I'm told that 'return' doesn't mean
what I think it means? At least not inside a block (or Proc.new)...

A block (except when it's a lambda) is meant to be looked at as though
it's a control structure in the function, the same as if it were an
ordinary loop. So the idea of `return` is to return from the function.
Use `next` to return a value early from the block.

arr2 = arr.collect{|ii| next 0 if ii == 3; ii+1}

4. And what's up with Ruby incorrectly naming their Map 'Hash'? Or is
my C.S. idea of a Hash too limited? Granted in Java they have HashMap,
but if you enter one value and get a second one out it is a Map,
regardless of how the keys are stored. A 'Hash' would instead be a type
of set.

Perhaps they should, but it would be a pain to change it now.

--Ken

···

On Wed, 04 Mar 2009 11:02:36 -0500, C. Dagnon wrote:

--
Chanoch (Ken) Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/

Hi --

C. Dagnon wrote:

Ruby has definite positives over Java and even other scripting
languages, but many negatives too. One negative is the inconsistency of
how rules seem to be applied in the language and accompanying toolsets.
Here are a few that have bitten me:

1. I almost immediately got started with Ruby on Rails and loved the
idea of partials, but then I found that the ||= idiom doesn't work on
partials' parameters.

<% my_param_a ||= 1 # Errors out
     my_param_a = my_param_a ? my_param_a : 1 # works
-%>

That seemed odd as I thought both were equivalent, and it broke some of
the trust I had for Ruby. Not as much as early Rails' use of 2 separate
variables for RAILS_ENV, but...

I can't duplicate that problem. What error message are you getting?

3. Originally I was taught that symbols were the salvation of memory and
key problems - and they certainly sounded like it. Up until the point a
few days later when one (Rails?) map used Symbols and another used
Strings. Ouch.
     Without any explicit typing abilities in the language (optional or
otherwise?) it seems like the only solution is to return to basic string
matches:
     regex = Regexp.compile("^#{matcher.to_s}$", Regexp::IGNORECASE)

You can use some shortcuts there:

   /^#{matcher}$/i

     key = map.keys.find{ |key| key.to_s =~ regex }
Yuck.

In 1.9, symbols can be matched against regular expressions. So you can do:

   [:a,:b,:c,:cat].grep(/a/)

I have mixed emotions about the string-like behavior of symbols in 1.9 (they have methods like #upcase and #succ), but it has the practical advantage of making it unnecessary to worry about which you've got if you're matching patterns.

Please let me know how I can supplement my possibly deficient Ruby
education :slight_smile: Relevant discussions or sections of "The Ruby Way"
appreciated!

There's a book or two due out soon... see below :slight_smile:

David

···

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (http://manning.com/black2\)

Ruby Training Atlanta! April 1-3, ruby training, atlanta, april 2009 - entp

C. Dagnon wrote:

4. And what's up with Ruby incorrectly naming their Map 'Hash'?

[snip]

A 'Hash' would instead be a type of set.

What do you mean in that last sentence?

···

--
Posted via http://www.ruby-forum.com/\.

> Or is my C.S. idea of a Hash too limited? Granted in Java they
> have HashMap, but if you enter one value and get a second one
> out it is a Map, regardless of how the keys are stored.

Hey, why aren't Arrays called Maps instead?

I've always found Java's naming of collections to be contrary to its idea of
OO in that it exposes implementation details, e.g. HashSet, LinkedHashSet
and TreeSet really ought to be called Set, OrderedSet and SortedSet to
reflect their intended use rather than their internal structure.

'Map' is unfortunately too vague a term and could be used to refer to
anything that maps a set of inputs to another set of outputs. You arguably
call arrays, lambdas, methods and even objects 'maps'. HashMap actually
isn't a bad name for this since it differentiates the data structure from
other mapping objects. I don't mind 'table' or 'hashtable'. 'Dictionary' is
a little restrictive in that it seems to imply string-only keys and seems to
relate to JavaScript-style objects rather than real hashtables. All said,
Hash isn't bad: it's an object that maps input to output by hashing the
input, which is all you need to know really.

Yossef Mendelssohn wrote:

There's been endless discussion and confusion about Symbols, Strings,
what they mean, what they should be used for, and their relation to
each other. Rails did not help with HashWithIndifferentAccess, though
I imagine they thought they would. But I don't want to start anything

I'm happy I didn't miss anything and sad to hear I'm not alone in that
confusion.

like that up. I just want to point out that a lot of that code is
unnecessary and could just be:

    key = map.keys.detect { |k| k.to_s.downcase ==
matcher.to_s.downcase }

Hmmm, what is 'detect'?

I had been doing that, but then I thought that compiling a single regex
would be less expensive than downcasing everything every time they got
compared. Not that the example I included appears in any of my code,
but I've been doing it for similar situations to allow for things like
case-indifferent parameters.

4. And what's up with Ruby incorrectly naming their Map 'Hash'?

...
At least they're not called "dictionaries", right? Am I right?

Yes, definitely right on that one.
Okay, so that was a Perl influence. Darn.

...
Hey, why aren't Arrays called Maps instead?

Sure arrays can be considered special kinds of maps. The ordering
problem could be solved by my_map.keys.sort.each instead of
my_array.each. The major difference I see is that Arrays have
type-checked and validated keys (non-negative integers), though I would
also say there's an assumption in how I've gotten used to using arrays
that if there is an element 5, there are elements 0-4 (even if nil).

Thanks for the reply!

-Chris

···

--
Posted via http://www.ruby-forum.com/\.

Ken Bloom wrote:

arr2 = arr.collect{|ii| next 0 if ii == 3; ii+1}

Should be:

    arr2 = arr.collect {|i| break if i == 3; i + 1 } # arr2 == nil

But, really, this does not seem the most sensible
way to implement anything except for illustrative
purposes.

···

--
Magic is insufficiently advanced technology.
--
Posted via http://www.ruby-forum.com/\.

Albert Schlef wrote:

C. Dagnon wrote:

4. And what's up with Ruby incorrectly naming their Map 'Hash'?

[snip]

A 'Hash' would instead be a type of set.

What do you mean in that last sentence?

A set simply contains values while mathematically a hash is a process
use to relate a value to a (hopefully advantageous) calculated value.
As used here, referring to a type of collection, a hash is the same as a
set: storing single, unrelated values. The hash's benefit is being able
to quickly check/retrieve individual items. For each of them there is
only one user-defined value involved per item in each collection.
(Typically users don't know or care what the hash algorithm or hash
values are thanks to encapsulation or other abstractions.)

Maps instead use one user-defined value to relate to a second
user-defined value by a user-defined relationship, the mapping. All 3
parts are knowledge defined external to the Map. The keys (and values)
can be stored as a hash set or ordered list or whatever makes sense.
Since the key-value relationship is user-defined you don't see generic
Map collections internally using an algorithm to magically go from key
to value: They have to concretely store the pairings so they know what
they are.

Interesting, though, as after you got me thinking about it I started to
wonder myself. Initially Hash and Map seem so distinctly alien to each
other that I can only hope the above proves clear enough.

Thank you for the question, and please let me know if I answered the
wrong one!

···

--
Posted via http://www.ruby-forum.com/\.

No, no, no. In Java, you have the interfaces Set, and SortedSet (no
OrderedSet, I suppose it would have exactly the same operations as a
Set), which don't define any operations, and AbstractSet which is a
helper class for people implementing sets.

Then you create instantiations HashSet, LinkedHashSet, TreeSet, which you
instantiate *knowing* what data you intend to use it for, and which
behind-the-scenes implementation has the best performance characteristics
for that data. (You *should* be allowed that choice, in general.) Then
you pass those around using the aforementioned implementation-agnostic
interfaces.

···

On Wed, 04 Mar 2009 12:01:27 -0500, James Coglan wrote:

[Note: parts of this message were removed to make it a legal post.]

> Or is my C.S. idea of a Hash too limited? Granted in Java they have
> HashMap, but if you enter one value and get a second one out it is a
> Map, regardless of how the keys are stored.

Hey, why aren't Arrays called Maps instead?

I've always found Java's naming of collections to be contrary to its
idea of OO in that it exposes implementation details, e.g. HashSet,
LinkedHashSet and TreeSet really ought to be called Set, OrderedSet and
SortedSet to reflect their intended use rather than their internal
structure.

--
Chanoch (Ken) Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/

You can also use String#casecmp to avoid making a new downcased string
object each time you do the comparison, e.g.

matcher.casecmp(k.to_s).zero?

···

On Wed, Mar 4, 2009 at 2:32 PM, C. Dagnon <c-soc-rubyforum@dagnon.net>wrote:

Yossef Mendelssohn wrote:
> key = map.keys.detect { |k| k.to_s.downcase == matcher.to_s.downcase
}

Hmmm, what is 'detect'?

I had been doing that, but then I thought that compiling a single regex
would be less expensive than downcasing everything every time they got
compared.

--
Tony Arcieri

Let's do some benchmarks:

···

El Miércoles, 4 de Marzo de 2009, C. Dagnon escribió:

I had been doing that, but then I thought that compiling a single regex
would be less expensive than downcasing everything every time they got
compared.

-----------

aaa="HolaQueTAL"
bbb="holaQUEtal"

Benchmark.realtime { aaa.downcase == bbb.downcase }

1.97887420654297e-05

Benchmark.realtime { aaa.casecmp(bbb) }

1.59740447998047e-05

Benchmark.realtime { aaa =~ /^#{bbb}$/i }

3.19480895996094e-05
---------------

Did you know the String#casecmp method? It seems to be the faster way.

--
Iñaki Baz Castillo

'detect' is a synonym for 'find' (or maybe it's the other way around).

I prefer to use the *ect methods when working with Enumerables instead
of the simpler/shorter synonyms. This is in part because they get some
consistency and connection, but also because Rails overrides some of
them on Enumerable-like association proxies. And some of them don't
even have non-ect synonyms.

  .detect -> .find
  .select -> .find_all
  .reject ->
  .collect -> .map
  .inject ->

···

On Mar 4, 3:32 pm, "C. Dagnon" <c-soc-rubyfo...@dagnon.net> wrote:

> key = map.keys.detect { |k| k.to_s.downcase ==
> matcher.to_s.downcase }

Hmmm, what is 'detect'?

--
-yossef

Iñaki Baz Castillo wrote:

···

El Miércoles, 4 de Marzo de 2009, C. Dagnon escribió:

I had been doing that, but then I thought that compiling a single regex
would be less expensive than downcasing everything every time they got
compared.

Let's do some benchmarks:
...
Did you know the String#casecmp method? It seems to be the faster way.

Nope, didn't hear about that, nor Benchmark.realtime. Thanks - these
look useful!

My only suggestion would be that we try it against 100, 10,000, and
larger sets of strings to see which is faster - this is over a
collection after all. I wasn't assuming a Regexp.compile would be
faster than other things for a single string compare.
--
Posted via http://www.ruby-forum.com/\.

Yossef Mendelssohn wrote:

···

On Mar 4, 3:32�pm, "C. Dagnon" <c-soc-rubyfo...@dagnon.net> wrote:

> � � key = map.keys.detect { |k| �k.to_s.downcase ==
> matcher.to_s.downcase }

Hmmm, what is 'detect'?

'detect' is a synonym for 'find' (or maybe it's the other way around).

I prefer to use the *ect methods when working with Enumerables instead
of the simpler/shorter synonyms. This is in part because they get some
consistency and connection, but also because Rails overrides some of
them on Enumerable-like association proxies. And some of them don't
even have non-ect synonyms.

  .detect -> .find
  .select -> .find_all
  .reject ->
  .collect -> .map
  .inject ->

Interesting... I hadn't learned about the *ect's. I have used collect
(never map, yuck), and now that I see it I think detect is a better word
for find as used here. While I think I can find a use for reject and
inject, select doesn't make much sense to me. I'll have to see if I can
fit that into my mindmap...

Thanks for that explanation Yossef!
--
Posted via http://www.ruby-forum.com/\.

Interesting. Now that I think about which versions I use, I don't have
a rule :-). I use:

find
select
reject
map
inject

So, no consistency or anything. Just the ones that I like better, I suppose :-D.

Jesus.

···

On Thu, Mar 5, 2009 at 4:41 PM, Yossef Mendelssohn <ymendel@pobox.com> wrote:

On Mar 4, 3:32 pm, "C. Dagnon" <c-soc-rubyfo...@dagnon.net> wrote:

> key = map.keys.detect { |k| k.to_s.downcase ==
> matcher.to_s.downcase }

Hmmm, what is 'detect'?

'detect' is a synonym for 'find' (or maybe it's the other way around).

I prefer to use the *ect methods when working with Enumerables instead
of the simpler/shorter synonyms. This is in part because they get some
consistency and connection, but also because Rails overrides some of
them on Enumerable-like association proxies. And some of them don't
even have non-ect synonyms.

.detect -> .find
.select -> .find_all
.reject ->
.collect -> .map
.inject ->

<snip>

'detect' is a synonym for 'find' (or maybe it's the other way around).

As so often genius goes undetected and unrewarded (but also
unpunished, while, when detected the later is not always the case).

But the idea of synonym not being a symmetric relation really made my day.

Thx. Yossef

N.B. I spelled your name correctly.
This time, do not push it too much though :wink:

R.

···

On Thu, Mar 5, 2009 at 4:41 PM, Yossef Mendelssohn <ymendel@pobox.com> wrote:

Think of it selecting the elements of the enumerable for which the block is
'true'.

Another analogy is to an SQL SELECT statement with the block taking the part
of the WHERE clause.

The *ect methods are evidence of the influence of Smalltalk on Ruby,
particularly inject, which is a Smalltalk variant on the more common reduce
operation which allows injection of an initial value outside of the receiver
into the sequence.

Ruby 1.9 adds the alias :reduce to Enumerable#inject.

···

On Thu, Mar 5, 2009 at 11:52 AM, C. Dagnon <c-soc-rubyforum@dagnon.net>wrote:

While I think I can find a use for reject and
inject, select doesn't make much sense to me. I'll have to see if I can
fit that into my mindmap..

--
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