Suggestion of Array#=== which improves case/when behaviour

Hello,

We already have :=== operator defined in Module, Range, Regexp and Proc
which is great for case/when statement. For all other objects :=== mean
:==.

My suggestion is to extend Array with === method:

Original behaviour:
[1,2,3] === [1,2,3] #=> true
[1,2,3] === [1,2,4] #=> false
[1,2,3] === 2 #=> false

Adding code: – this code is similar to Array#== , but uses :=== for
comparing each element
class Array
def ===( arg )
arg.is_a?(Array) && self.size == arg.size && (0…size).all?{|i|
self[i] === arg[i] }
end
end

After adding code:
[1,2,3] === [1,2,3] #=> true
[1,2,3] === 2 #=> false

[1,2,Object] === [1,2,3] #=> true
[1,2,/^some/] === [1,2,“some string”] #=> true
[1,2,[Symbol, Array]] === [1,2,[:key, []]] #=> true <---- this
is an example of deep structure matching

You can see other examples at
http://github.com/dmitryelastic/dumb-patterns-matching/blob/master/patterns_matching.rb
and http://github.com/dmitryelastic/dumb-patterns-matching

“Set” class has meaning close to “Range” class. If we will define
Set#=== as

class Set
def ===( arg )
self.any?{|template| template === arg }
end
end

we will be able to write case/when code in haskell-like pattern-matching
style. here is an example of simple s-expression evaluator from my page:

Sexp = Set[Array, Numeric] # means - array or number
Boolean = Set[true, false]
Sexpbool = Set[Array] | Boolean # means - array or true or false

def evale(e) # function which will evaluate S-Expression
case e
when Numeric, Boolean then e
when [:-, Sexp] then - evale(e[1])
when [:-, Sexp, Sexp] then evale(e[1]) - evale(e[2])
when [:+, Sexp, Sexp] then evale(e[1]) + evale(e[2])
when [:*, Sexp, Sexp] then evale(e[1]) * evale(e[2])
when [:**, Sexp, Sexp] then evale(e[1]) ** evale(e[2])
when [:>, Sexp, Sexp] then evale(e[1]) > evale(e[2])
when [:if, Sexpbool, Sexp, Sexp] then evale(e[1]) ?evale(e[2]) :
evale(e[3])
when Object then fail(“something went wrong”)
end
end

def test_exp_eval
exp = [:*, [:-, 9, 2], [:+, 8, [:-, 2]]] # -> (9 - 2) * (2 + 4) = 42
assert_equal 42, evale(exp)
exp2 = [:if, true, 10, 20]
assert_equal 10, evale(exp2)
exp3 = [:if, [:>, [:, 5, 5], 4000], 1, 2] # -> 2 , because 4000 >
5
5
assert_equal 2, evale(exp3)
end

Dmitry V. wrote:

Hello,

We already have :=== operator defined in Module, Range, Regexp and Proc
which is great for case/when statement. For all other objects :=== mean
:==.

My suggestion is to extend Array with === method:

Original behaviour:
[1,2,3] === [1,2,3] #=> true
[1,2,3] === [1,2,4] #=> false
[1,2,3] === 2 #=> false

Adding code: – this code is similar to Array#== , but uses :=== for
comparing each element
class Array
def ===( arg )
arg.is_a?(Array) && self.size == arg.size && (0…size).all?{|i|
self[i] === arg[i] }
end
end

After adding code:
[1,2,3] === [1,2,3] #=> true
[1,2,3] === 2 #=> false

[1,2,Object] === [1,2,3] #=> true
[1,2,/^some/] === [1,2,“some string”] #=> true
[1,2,[Symbol, Array]] === [1,2,[:key, []]] #=> true <---- this
is an example of deep structure matching

You can see other examples at
http://github.com/dmitryelastic/dumb-patterns-matching/blob/master/patterns_matching.rb
and http://github.com/dmitryelastic/dumb-patterns-matching

So, my question is: Do you agree that Array#=== can be useful for us?

My opinion is that it can be in ruby std library along with
Proc#===(which is already in ruby 1.9 –
http://www.aimred.com/news/developers/2008/08/14/unlocking_the_power_of_case_equality_proc/)

Dmitry V. wrote:

Hello,

We already have :=== operator defined in Module, Range, Regexp and Proc
which is great for case/when statement. For all other objects :=== mean
:==.

My suggestion is to extend Array with === method:

I long ago did something similar, but much more extensive; I created a
large pattern-matching language/library for ruby data structures
called Reg. Instead of changing the existing Array#===, I created a
new class, Reg::Array, which has the functionality you want. A
Reg::Array can be constructed by enclosing the patterns of interest
between +[ and ].

You should have a look at Reg; you can install the gem:
gem install reg
or take a look at the github project, which contains newer (and buggier)
code:
http://github.com/coatl/reg

On 12/17/09, Dmitry V. [email protected] wrote:

“Set” class has meaning close to “Range” class. If we will define
Set#=== as

class Set
def ===( arg )
self.any?{|template| template === arg }
end
end

Personally, I would rather see Set#=== be an alias for include?. The
alternation semantics that you want here are provided in Reg by
Reg::Or, which is usually created by gluing together individual
matchers that you want with the | operator. So it’d look like:
Sexp = Array|Numeric
instead of:
Sexp = Set[Array, Numeric]

I would absolutely love if Array recursively performed #=== on its
arguments. AFAICT Array#=== is practically identical to Array#==

Hi,

It doesn’t look too usefull to me like that. (I mean using classes to
compare).

For this purpose I wrote something like:

Analyse arguments given to a method(*args)

Exemple:

def m(*args)

case args

when ARGS[Complex]

m(Complex.new(1,1))

when ARGS[Integer, Boolean]

m(2, true)

when ARGS[[Numeric, Float], String]

m([1, 3.14], “Hello World!”)

when ARGS[[[Integer, Integer],[Float, Rational ]]]

m( [[1 , 2 ],[3.0 , Rational(1,2)]])

end

end

module Boolean; end
class FalseClass; include Boolean; end
class TrueClass; include Boolean; end

class ARGS
def initialize(*constraints)
@constraints = constraints
end

def ARGS.[](*constraints)
    ARGS.new(*constraints)
end

def match?(args)
    return false unless @constraints.length == args.length
    @constraints.each_with_index { |constraint, i|
        case constraint
        when Module
            unless args[i].is_a?(constraint)
                return false
            end
        when Array
            unless args[i].is_a?(Array) &&

ARGS[*constraint].match?(args[i])
return false
end
end
}
true
end

def ===(args)
    match?(args)
end

end


Some mails ago, I also thought Array#=== implemented a OR-related test
like
in:
case 2
when -1,1,2

end

But that seems to be more a feature of the “block” case.

So, I think this trick can be useful in special “cases”, but I don’t see
enough interest to do that for the Ruby core.

Any exemples more attractive ?

2009/12/18 Dmitry V. [email protected]

Hi –

On Sat, 19 Dec 2009, Tony A. wrote:

I would absolutely love if Array recursively performed #=== on its
arguments. AFAICT Array#=== is practically identical to Array#==

It’s an interesting idea but I wonder how useful it would be, compared
to having case equality be essentially == for Arrays. I just can’t
imagine that many cases of, say:

case array
when [/abc/, Fixnum, “hi”]

etc. I guess it might occasionally be used for checking regex matches
on a bunch of strings at the same time:

case user_data
when [first_name_re, last_name_re, age_re, email_re]

or something – but even in such a case, you’d probably want to do it
in such a way that you could isolate which one went wrong.

On the other hand, something like:

case user_data
when other_user_data

seems like a more likely comparison scenario.

David

On Dec 19, 2009, at 10:32 AM, Rick DeNatale wrote:

I’ve been amazed by how subtly disruptive, seemingly simple changes
like the result of Array#to_s between Ruby 1.8 and 1.9 can be
http://talklikeaduck.denhaven2.com/2009/10/27/its-the-little-things

I still don’t understand that particular change. The 1.8 semantics of
Array#to_s were much more useful in my mind than the 1.9 semantics.

Gary W.

On 12/19/09, Rick DeNatale [email protected] wrote:

I’ve been amazed by how subtly disruptive, seemingly simple changes
like the result of Array#to_s between Ruby 1.8 and 1.9 can be
http://talklikeaduck.denhaven2.com/2009/10/27/its-the-little-things

I added this to my tests for 1.9 porting. It at least makes the
Array#to_s problems readily apparent. Not intended as a permanent
measure.

if defined? ::RUBY_VERSION and ::RUBY_VERSION[/^\d+.\d+/].to_f>=1.9
class ::Array
alias to_s_without_semantics_changed_warning to_s

def to_s
  warn "calling Array#to_s from #{caller.first}; semantics have 

changed"
to_s_without_semantics_changed_warning
end
end
end

On Sat, Dec 19, 2009 at 6:13 AM, David A. Black [email protected]
wrote:

case array
when [/abc/, Fixnum, “hi”]

My imagination runs instead to all the possibilities of breaking
existing code if such a change to a fundamental class were made.

I’ve been amazed by how subtly disruptive, seemingly simple changes
like the result of Array#to_s between Ruby 1.8 and 1.9 can be
http://talklikeaduck.denhaven2.com/2009/10/27/its-the-little-things

It would be better I think to have a new class which acted like an
Array and did recursive === for the seemingly rare cases where this is
needed. And I don’t think that such a class need be part of the
standard library. That’s the beauty of a language like Ruby,
programmers can extend it for themselves to fit THEIR purposes, which
often are different from MY purposes.


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

2009/12/19 Gary W. [email protected]

Gary W.

I don’t think so, it became quite a mess when you did:
Values: [1, :b, “cd”]
1.8: Values: 1bcd
1.9: Values: [1, :b, “cd”]
I think the second shows better it’s an Array.

Clearly Array#to_s was a (useful) shortcut to Array#join.

But I think that wasn’t a way to do what you wanted. #to_s is made to
show
the result in a String, usually on screen. It’s quite different than
wanting
to join every element with the following, what is the sense of #join.

On Dec 20, 2009, at 11:03 AM, Benoit D. wrote:

I don’t think so, it became quite a mess when you did:
Values: [1, :b, “cd”]
1.8: Values: 1bcd
1.9: Values: [1, :b, “cd”]
I think the second shows better it’s an Array.

A) making an incompatible change to something so basic as Array#to_s
is/was a bad idea
B) Array#inspect was already available for debugging output
C) Array#to_s in 1.8 was useful for converting tree structures (nested
arrays) to strings (in-order traversal).

But I think that wasn’t a way to do what you wanted. #to_s is made to show
the result in a String, usually on screen. It’s quite different than wanting
to join every element with the following, what is the sense of #join.

It seems intuitive to me that the string representation of a list would
simply be the concatenation of the string representation of the
individual elements. If I wanted extra punctuation to aid in debugging
then Array#inspect was always available and if I wanted to include
separators of some sort I had Array#join. The advantage of Array#to_s vs
Array#join (for null separators) is that it integrates quite nicely with
string interpolation as well as many of the IO output primitives.

Hello,

Does ruby have a DESTROY method in its class? like,

class Myclass
def DESTROY
something
end
end

Thanks.

On Sun, Dec 20, 2009 at 10:23 PM, Tech W. [email protected] wrote:

Hello,

Does ruby have a DESTROY method in its class? like,

class Myclass
 def DESTROY
   something
 end
end

There isn’t a “DESTROY” (or “destroy”) method defined by default. They
are legal names for methods you define (though DESTROY conventionally
would be a constant, not a method.)

You may be looking for C+±style destructors, which given the
difference in memory management and object lifecycle between Ruby and
C++ aren’t really present in Ruby.

You’d probably get more useful answers asking for what you want to DO
rather than looking for a method name.

Tech W. wrote:

Does ruby have a DESTROY method in its class? like,

class Myclass
def DESTROY
something
end
end

Take a look at finalizers[1]

Edward

  1. http://ruby-doc.org/core/classes/ObjectSpace.html
end

end

Thanks.

No, objects in Ruby are simply garbage collected
when they go out of scope. It is never neccesary to explicitly
destroy an object. If there is any work you need done
before an object goes away, you had best do it before you let
it out of scope.

On 2009-12-21, Tech W. [email protected] wrote:

for example, I openned a database handler in a class, and new an object
from this class, when the object go out of the scope, I want it close
the database handler automatically. so how to implement this in Ruby?
thanks again.

You don’t. When you’re done, you close it. More likely, you build your
class so that you would do something like:

foo.database_get do |db|
db.do_this
db.do_that
end

and database_get closes the database handle when it’s done.

-s

No, objects in Ruby are simply garbage collected
when they go out of scope. It is never neccesary to explicitly
destroy an object. If there is any work you need done
before an object goes away, you had best do it before you let
it out of scope.

for example, I openned a database handler in a class, and new an object
from this class, when the object go out of the scope, I want it close
the database handler automatically. so how to implement this in Ruby?
thanks again.

Regards,
W.

2009/12/21 Tech W. [email protected]:

No, objects in Ruby are simply garbage collected
when they go out of scope. It is never neccesary to explicitly
destroy an object. If there is any work you need done
before an object goes away, you had best do it before you let
it out of scope.

for example, I openned a database handler in a class, and new an object
from this class, when the object go out of the scope, I want it close the
database handler automatically. so how to implement this in Ruby? thanks
again.

There is keyword “ensure”. You can also use blocks for this like
File.open does. You can read up on this here:
http://blog.rubybestpractices.com/posts/rklemme/002_Writing_Block_Methods.html

Kind regards

robert