Inheritance Question

Well, the way Matrix is setup, it makes even using DelegateClass
difficult.

Well, this is not the way that Matrix is setup, the problem I think is if
you write

   m = MyMatrix[[1,2],[3,4]]
   n = MyMatrix[[1,2],[3,4]]
   o = m + n

`m' and `n' are instance of MyMatrix but `o' will be instance of Matrix
and this is probably not what you want.

Guy Decoux

[snip]

Well, the way Matrix is setup, it makes even using DelegateClass
difficult.
[snip]

i’ve come up against this on several occasions too.

it seems to me that a good general rule for writing classes seems to be :

···

**

‘never call Class.method from any instance method lest ye be uninheritable’

**

for instance, if all calls to Matrix.method made from inside Matrix instance
methods are replaced with type.method - Matrix works identically and becomes
inheritable. to me this seems abosolutely reasonable, though some would
claim class designers might want to enforce the return of a specific object
type from certain methods. i would say this has NO place in Ruby for the
following reasons

  • Ruby classes are open so the whole thing is kindof moot any how

  • 99% of the time you have the actual sources - thus even ‘mooter’ :wink:

  • your class will work the same with ‘type.method’ vs ‘Class.method’

  • if someone is inheriting your class they are breaking encapsulation anyhow
    (since inheritence opens up some of a class’s internals to the inheriter)
    and it’s up to them to maintain the semantics and behaviour of the
    inherited class … it cannot affect the original

in fact, writing ‘Class.method’ from inside instance methods only encourages
people to hack your class to bits in an environment where both the sources and
Classes are open.

my 2 cents.

-a

====================================

Ara Howard
NOAA Forecast Systems Laboratory
Information and Technology Services
Data Systems Group
R/FST 325 Broadway
Boulder, CO 80305-3328
Email: ahoward@fsl.noaa.gov
Phone: 303-497-7238
Fax: 303-497-7259
====================================

I agree.
I think for 1.7 and forward, it should class.method instead of
type.method?

Jim

···

On Saturday, 14 December 2002 at 1:50:22 +0900, ahoward wrote:

[snip]

Well, the way Matrix is setup, it makes even using DelegateClass
difficult.
[snip]

**

‘never call Class.method from any instance method lest ye be uninheritable’

**

for instance, if all calls to Matrix.method made from inside Matrix instance
methods are replaced with type.method - Matrix works identically and becomes
inheritable. to me this seems abosolutely reasonable, though some would
claim class designers might want to enforce the return of a specific object
type from certain methods. i would say this has NO place in Ruby for the
following reasons


Jim Freeze

Some don’t prefer the pursuit of happiness to the happiness of pursuit.

for instance, if all calls to Matrix.method made from inside Matrix instance
methods are replaced with type.method - Matrix works identically and becomes
inheritable.

Matrix is inheritable : the problem is with delegation

Guy Decoux

require ‘matrix’

#the problem
class MyMatrix < Matrix
end

mm = MyMatrix[ [42] ]
p mm.type # >> MyMatrix
p mm.to_f.type # >> Matrix

#the fix
class Matrix
def collect
rows = @rows.collect{|row| row.collect{|e| yield e}}
#Matrix.rows(rows, false)
type.rows(rows, false)
end
end

mm = MyMatrix[ [42] ]
p mm.type # >> MyMatrix
p mm.to_f.type # >> MyMatrix

i thinks it’s a problem when you inherit from a class and cannot re-use the
instance methods when they ‘jump’ outside the inherited class… eg. the
only way around this is to completely rewrite evey Matrix instance method
which refers to a Matrix class method. technically this IS inheritable but
it’s a bitter pill to swallow…

-a

···

On Sat, 14 Dec 2002, ts wrote:

for instance, if all calls to Matrix.method made from inside Matrix instance
methods are replaced with type.method - Matrix works identically and becomes
inheritable.

Matrix is inheritable : the problem is with delegation

====================================

Ara Howard
NOAA Forecast Systems Laboratory
Information and Technology Services
Data Systems Group
R/FST 325 Broadway
Boulder, CO 80305-3328
Email: ahoward@fsl.noaa.gov
Phone: 303-497-7238
Fax: 303-497-7259
====================================

  mm = MyMatrix[ [42] ]
  p mm.type # >> MyMatrix
  p mm.to_f.type # >> MyMatrix

     a = mm + Matrix[[12]] # p a.class ???
     b = Matrix[[12]] + mm # p b.class ???
     c = mm + mm # p c.class ???

Guy Decoux

The print results are all Matrix. I don’t understand your point.

···

On Saturday, 14 December 2002 at 2:54:51 +0900, ts wrote:

mm = MyMatrix[ [42] ]
p mm.type # >> MyMatrix
p mm.to_f.type # >> MyMatrix

 a = mm + Matrix[[12]] # p a.class ???
 b = Matrix[[12]] + mm # p b.class ???
 c = mm + mm           # p c.class ???


Jim Freeze

 a = mm + Matrix[[12]] # p a.class ???
 b = Matrix[[12]] + mm # p b.class ???
 c = mm + mm           # p c.class ???

class Matrix
def +(m)
case m
when Numeric
#Matrix.Raise ErrOperationNotDefined, “+”
type.Raise ErrOperationNotDefined, “+”
when Vector
#m = Matrix.column_vector(m)
m = type.column_vector(m)
when Matrix
else
x, y = m.coerce(self)
return x + y
end

#Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
type.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size

rows = (0 .. row_size - 1).collect {
  >i>
  (0 .. column_size - 1).collect {
>j>
self[i, j] + m[i, j]
  }
}
#Matrix.rows(rows, false)
type.rows(rows, false)

end
end

mm = MyMatrix[ [42] ]
p mm.type # >> MyMatrix
p mm.to_f.type # >> MyMatrix

p ((mm + Matrix[[12]]).type) # >> MyMatrix
p ((Matrix[[12]] + mm).type) # >> Matrix
p ((mm + mm).type ) # >> MyMatrix

this is exactly what i was refering to :

all references to ‘Matrix.method’ from INSIDE instance methods need to
bechanged to ‘type.method’ and all is well…

i’ll admit that

MyMatrix + Matrix → MyMatrix
Matrix + MyMatrix → Matrix

is slightly counterintuitive… but only if you view the additive associtive
property of numbers as universally applicable to objects, which it is of
course not. if one realizes the Object + AnOther is really
Object.+(AnOther) is makes perfect sense.

-a

···

On Sat, 14 Dec 2002, ts wrote:

====================================

Ara Howard
NOAA Forecast Systems Laboratory
Information and Technology Services
Data Systems Group
R/FST 325 Broadway
Boulder, CO 80305-3328
Email: ahoward@fsl.noaa.gov
Phone: 303-497-7238
Fax: 303-497-7259
====================================

mm = MyMatrix[ [42] ]
p mm.type # >> MyMatrix
p mm.to_f.type # >> MyMatrix

     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

a = mm + Matrix[[12]] # p a.class ???
b = Matrix[[12]] + mm # p b.class ???
c = mm + mm # p c.class ???

The print results are all Matrix. I don't understand your point.

Well if it give Matrix, it must be Matrix also for

  a = mm * 1.0

This is not the result given

Guy Decoux

···

On Saturday, 14 December 2002 at 2:54:51 +0900, ts wrote:

This is acceptable. I can work around this. I did in C++.
The way it is now, Matrix is essentially broken for my use.

···

On Saturday, 14 December 2002 at 3:51:45 +0900, ahoward wrote:

On Sat, 14 Dec 2002, ts wrote:

p ((mm + Matrix[[12]]).type) # >> MyMatrix
p ((Matrix[[12]] + mm).type) # >> Matrix
p ((mm + mm).type ) # >> MyMatrix

all references to ‘Matrix.method’ from INSIDE instance methods need to
bechanged to ‘type.method’ and all is well…

MyMatrix + Matrix → MyMatrix
Matrix + MyMatrix → Matrix


Jim Freeze

What good is a ticket to the good life, if you can’t find the
entrance?

p ((mm + Matrix[[12]]).type) # >> MyMatrix
p ((Matrix[[12]] + mm).type) # >> Matrix
p ((mm + mm).type ) # >> MyMatrix

Now you have a big problem, because this not what ruby do

pigeon% cat b.rb
#!/usr/bin/ruby
class A < Array; end
a = A.new
p ((a+).class)
p ((+a).class)
p ((a+a).class)
pigeon%

pigeon% b.rb
Array
Array
Array
pigeon%

this is exactly what i was refering to :

all references to 'Matrix.method' from INSIDE instance methods need to
bechanged to 'type.method' and all is well...

you have written a class which break completely the way that ruby work,
and all persons will be surprised by your strange class.

course *not*. if one realizes the Object + AnOther is really
Object.+(AnOther) is makes perfect sense.

it make perfect sense in *your* language, but this language *is NOT* ruby.

Guy Decoux

This is acceptable. I can work around this. I did in C++.

  ruby is not C++, and thanks for that.

Guy Decoux

Don’t you mean that this is how Array was implemented, not what
ruby does. Maybe Array is not doing the right thing by not
returning self (I’m sure someone will correct me here if I am wrong).
The language doesn’t force one to always return the base class.

class A
def +(o)
self
end
end

class B < A
def +(o)
self
end
end

a=A.new
b=B.new

p ((a+a).class) #=> A
p ((b+b).class) #=> B
p ((a+b).class) #=> A
p ((b+a).class) #=> B

···

On Saturday, 14 December 2002 at 19:45:03 +0900, ts wrote:

p ((mm + Matrix[[12]]).type) # >> MyMatrix
p ((Matrix[[12]] + mm).type) # >> Matrix
p ((mm + mm).type ) # >> MyMatrix

Now you have a big problem, because this not what ruby do

pigeon% cat b.rb
#!/usr/bin/ruby
class A < Array; end
a = A.new
p ((a+).class)
p ((+a).class)
p ((a+a).class)
pigeon%

pigeon% b.rb
Array
Array
Array
pigeon%


Jim Freeze

Don't you mean that this is how Array was implemented, not what

Vect and Matrix are implemented via Array. It can be strange if Vect do
something and Array do another thing.

The language doesn't force one to always return the base class.

I know this but there are other classes in ruby which do like Array (don't
remember actually but this seems to be a voluntary choice)

  def +(o)
    self
  end

This is you which has written this : I'm not really sure that all persons
will write the same thing.

Guy Decoux

ruby does. Maybe Array is not doing the right thing by not
returning self (I'm sure someone will correct me here if I am wrong).

[ruby-talk:11575] and the rules was simpler than yours :-)))

Guy Decoux

… and yet wouldn’t it be great if C++ was Ruby? :slight_smile:

···

On Sat, Dec 14, 2002 at 07:50:47PM +0900, ts wrote:

This is acceptable. I can work around this. I did in C++.

ruby is not C++, and thanks for that.


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

One tree to rule them all,
One tree to find them,
One tree to bring them all,
and to itself bind them.
– Gavin Koch gavin@cygnus.com

Don’t you mean that this is how Array was implemented, not what

Vect and Matrix are implemented via Array. It can be strange if Vect do
something and Array do another thing.

cat v.rb
require ‘matrix’

v1 = Vector[1]
v2 = Vector[2]
p ((v1+v2).class)

ruby v.rb
Vector

Here, Vector extends array and returns a Vector and NOT Array when
adding two Vectors. I don’t see why an extension of Matrix should not
return the super class. Same for Array.

The language doesn’t force one to always return the base class.

I know this but there are other classes in ruby which do like Array (don’t
remember actually but this seems to be a voluntary choice)

I agree that in general, it would be difficult to ensure that every
library returns self for chainable methods. But, I do think it is a
good practice, especially if you expect your class to used as a base
class.

For the case of Matrix, it makes it impracticle to be used as a base
class. To extend the class, I would have to do it directly and hope
that I don’t cause any problems. But when I am writing numerical code,
I usually have accuracy as my primary goal, so I am unlikely to extend
the class directly because it may have side effects.

···

On Saturday, 14 December 2002 at 22:00:53 +0900, ts wrote:


Jim Freeze

v1 = Vector[1]
v2 = Vector[2]
p ((v1+v2).class)

class A < Array; end

Array + Array ===> Array
Array + A ===> Array

class V < Vector; end
Vector + Vector ===> Vector
Vector + V ===> Vector

Vector work like Array

Here, Vector extends array and returns a Vector and NOT Array when

Vector don't extend Array, it implement a specialized Array

pigeon% ruby -rmatrix -e 'p Vector.ancestors'
[Vector, ExceptionForMatrix, Object, Kernel]
pigeon%

Guy Decoux