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

···

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

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

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

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

···

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

Dmitry Vazhov 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:
  GitHub - coatl/reg: Reg is a library and language for pattern matching in ruby data structures. Reg provides Regexp-like match and match-and-replace for all data structures (particularly Arrays, Objects, and Hashes), not just Strings.

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

···

On 12/17/09, Dmitry Vazhov <dmitryelastic@gmail.com> wrote:

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 Vazhov <dmitryelastic@gmail.com>

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

Aimred - Unlocking The Power Of Case Equality: Proc#===
)

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

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

···

On Fri, Dec 18, 2009 at 4:16 PM, Caleb Clausen <vikkous@gmail.com> wrote:

> Dmitry Vazhov 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:
GitHub - coatl/reg: Reg is a library and language for pattern matching in ruby data structures. Reg provides Regexp-like match and match-and-replace for all data structures (particularly Arrays, Objects, and Hashes), not just Strings.

On 12/17/09, Dmitry Vazhov <dmitryelastic@gmail.com> 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]

--
Tony Arcieri
Medioh! A Kudelski Brand

Hi --

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 Sat, 19 Dec 2009, Tony Arcieri wrote:

--
David A. Black
Senior Developer, Cyrus Innovation Inc.
THE COMPLEAT RUBYIST, Ruby training with Black/Brown/McAnally!
January 22-23, Tampa, Florida
Info and registration at http://www.thecompleatrubyist.com

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.

···

On Sat, Dec 19, 2009 at 6:13 AM, David A. Black <dblack@rubypal.com> wrote:

Hi --

On Sat, 19 Dec 2009, Tony Arcieri 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"]

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

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 Wright

···

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 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 12/19/09, Rick DeNatale <rick.denatale@gmail.com> 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 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.

···

2009/12/19 Gary Wright <gwtmp01@mac.com>

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 Wright

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.

···

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

Hello,

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

class Myclass
    def DESTROY
       something
    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.

···

-----Original Message-----
From: Tech W. [mailto:TechWWW@yahoo.com.cn]

Hello,

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

class Myclass
    def DESTROY
       something
    end
end

Thanks.

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.

···

On Sun, Dec 20, 2009 at 10:23 PM, Tech W. <TechWWW@yahoo.com.cn> wrote:

Hello,

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

class Myclass
def DESTROY
something
end
end

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. module ObjectSpace - RDoc Documentation

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.

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

···

On 2009-12-21, Tech W. <TechWWW@yahoo.com.cn> 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.

--
Copyright 2009, all wrongs reversed. Peter Seebach / usenet-nospam@seebs.net
| Seebs.Net <-- lawsuits, religion, and funny pictures
Fair game (Scientology) - Wikipedia <-- get educated!

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

···

2009/12/21 Tech W. <TechWWW@yahoo.com.cn>:

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.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/