Things That Newcomers to Ruby Should Know (10/16/02)

Actually, the way you describe ‘+=’ makes sense to me. It is what I would
have expected. If I’m refering to one object in two different ways (that
is, two different variables), why not have side-effects? That doesn’t seem
so very odd. Granted I’ve been doing OO stuff for about 17 years, but
still, it’s not like it took that long to grok objects and references.

Drew

···

-----Original Message-----
From: William Djaja Tjokroaminata [mailto:billtj@z.glue.umd.edu]
Sent: Wednesday, October 23, 2002 12:00 PM
To: ruby-talk@ruby-lang.org
Subject: Re: Things That Newcomers to Ruby Should Know (10/16/02)

Hi,

As already been pointed out, this is because in Ruby when a
variable is assigned to another variable, the new variable
simply refers to the same object that the old variable refers to:

a = AnObject.new
b = a    # b really refers to the same, identical AnObject as a

Therefore, if ‘+=’ means ‘append()’, then what you will have is

b += anotherObj    # a will also be a = a.append(anotherObj)

The only safe/natural way of having ‘+=’ to mean ‘append()’
is by changing the semantic in Ruby by having the variable
assignment operator to invoke some copy method:

# Not a Ruby code
a = AnObject.new
b = a    # b = a.copy()
b += anotherObj    # b = b.append(anotherObj), a unchanged

But Ruby does not work that way; you have to use C++ if that
is really the intention.

Regards,

Bill

Hi,

Actually Ruby still gives you a choice. When you have

a = AnObject.new
b = a

If you don’t want side effects, you simply type

b += anotherObj

and if you want side effects, you may type

b << anotherObj    # if the '<<' operator is defined for AnObject

So basically, in Ruby by default there are no side effects through
‘+=’ (I guess to be safer, if not natural). Some methods (like ‘<<’ and
those ending in ‘!’) usually modify the original object directly, and
these methods create side effects. And the beauty of Ruby is, in my
opinion, you can create your own methods or modify existing ones to have
side effects. So I think you still have a lot of freedom in Ruby; but by
default, Ruby directs you to the “safer” way :slight_smile: .

Regards,

Bill

P.S. In C++ terms, Ruby never overloads the assignment operator, Ruby by
default does not provide copy constructors, Ruby always overloads the
‘+=’ operator simply in direct connection to the corresponding ‘+’ method,
and Ruby allows you to overload many other methods that may look like
operator (such as ‘<<’).

···

===========================================================================
“Mills Thomas (app1tam)” app1tam@ups.com wrote:

Actually, the way you describe ‘+=’ makes sense to me. It is what I would
have expected. If I’m refering to one object in two different ways (that
is, two different variables), why not have side-effects? That doesn’t seem
so very odd. Granted I’ve been doing OO stuff for about 17 years, but
still, it’s not like it took that long to grok objects and references.

Drew

Hi –

Hi,

Actually Ruby still gives you a choice. When you have

a = AnObject.new
b = a

If you don’t want side effects, you simply type

b += anotherObj

and if you want side effects, you may type

b << anotherObj    # if the '<<' operator is defined for AnObject

True, although the term “side effects” might be ascribing more
weirdness to it than there really is :slight_smile: Anyway, another possible
factor here is that the += idiom harbors a potential snag that I don’t
think has been mentioned in this thread (though it has been the
subject of threads), namely the conversion of the result to the class
of the argument. For example:

class S < String
def speak
puts “Hello, I contain: #{self}”
end
end

a = S.new(“one”)
b = a

a.speak # Hello, I contain: one

a += " two"

b.speak # Hello, I contain: one
a.speak # NameError: no such method (a is now a String)

David

···

On Thu, 24 Oct 2002, William Djaja Tjokroaminata wrote:


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

Hi David,

Your example is really interesting (surprising to me, actually). Aren’t
we having fun doing “Ruby language analysis”? :slight_smile:

I think your example can be shortened to this:

class S < String
def speak
puts "Hello, I contain: #{self}"
end
end

a = S.new(“one”)
puts “a.class = #{a.class}” # a.class = S
puts “(a+‘two’).class = #{(a+‘two’).class}” # (a+‘two’).class = String

Well, a “mechanical” explanation may be that class S calls the String
class ‘+’ method, which always creates a new object of class
String. But is it good from the “philosophical” point of view that

Class_A + Class_B = Class_B (or even some other Class_C)

and not always Class_A?

(I would care less if the method is other than ‘+’…)

Regards,

Bill

I also find this interesting, as it's a side-effect of subclassing I hadn't
thought about.

Somewhere deep in the innards of String#+ it is doing the equivalent of a
String.new; should it be doing a self.class.new instead?

Put more philosophically: is it the responsibility of a class author to
consider the requirements of possible future subclasses, in particular to
make sure that inherited methods have the 'right' behaviour in the context
of a subclass?

If not, then the subclass will end up having to wrap those methods - i.e.

  class S
    def +(arg)
      S.new(super)
    end
  end

That's ugly, and it seems like it was hardly worth inheriting the method in
the first place. [1]

The 'new' method which was inherited by S (or at least gives the appearance
of being inherited) doesn't need a wrapper though: S.new returns an S, not a
String. Perhaps that's why it's surprising that the inherited S#+ returns a
String not an S.

Regards,

Brian.

[1] That doesn't apply to _all_ inherited methods - e.g. the inherited '<=>'
is perfectly good - just methods which return String in this case

···

On Thu, Oct 24, 2002 at 12:42:20PM +0900, William Djaja Tjokroaminata wrote:

I think your example can be shortened to this:

  class S < String
    def speak
      puts "Hello, I contain: #{self}"
    end
  end
       
  a = S.new("one")
  puts "a.class = #{a.class}" # a.class = S
  puts "(a+'two').class = #{(a+'two').class}" # (a+'two').class = String

Well, a "mechanical" explanation may be that class S calls the String
class '+' method, which *always* creates a new object of class
String. But is it good from the "philosophical" point of view that

    Class_A + Class_B = Class_B (or even some other Class_C)

and not always Class_A?

(I would care less if the method is other than '+'...)

Hi Brian,

I agree with everything that you said. I guess in a typed language such
as C++, this is not a problem, because the same data (i.e., bit
patterns) can be interpreted differently based on the type of the variable
that is used to access the data. In a “typeless” language such as Ruby,
on the other hand, the type itself is carried in the data, and therefore I
got this “surprise”.

I personally don’t know which is the “right” way to do OO design. Whereas
a question such as the lack of Boolean parent class in Ruby is
probably more theoretical than practical, a question like this is I think
very practical, because it dictates the whole OO design. I am rather
disappointed actually, because very few (or almost none of the) people
who usually discussed OO-related issues state their opinions. (Or
probably this is just one of the “unsolved problems” in Ruby, along with
others like private variables and block local variables?)

Regards,

Bill

···

Brian Candler B.Candler@pobox.com wrote:

I also find this interesting, as it’s a side-effect of subclassing I hadn’t
thought about.

Somewhere deep in the innards of String#+ it is doing the equivalent of a
String.new; should it be doing a self.class.new instead?

Put more philosophically: is it the responsibility of a class author to
consider the requirements of possible future subclasses, in particular to
make sure that inherited methods have the ‘right’ behaviour in the context
of a subclass?

If not, then the subclass will end up having to wrap those methods - i.e.

class S
def +(arg)
S.new(super)
end
end

That’s ugly, and it seems like it was hardly worth inheriting the method in
the first place. [1]

The ‘new’ method which was inherited by S (or at least gives the appearance
of being inherited) doesn’t need a wrapper though: S.new returns an S, not a
String. Perhaps that’s why it’s surprising that the inherited S#+ returns a
String not an S.

Regards,

Brian.

[1] That doesn’t apply to all inherited methods - e.g. the inherited ‘<=>’
is perfectly good - just methods which return String in this case

Brian Candler wrote:

Somewhere deep in the innards of String#+ it is doing the equivalent of a
String.new; should it be doing a self.class.new instead?

But wouldn’t this be a problem if the subclass’s constructor had different
access/arity to that of the base class?

Put more philosophically: is it the responsibility of a class author to
consider the requirements of possible future subclasses, in particular to
make sure that inherited methods have the ‘right’ behaviour in the context
of a subclass?

If not, then the subclass will end up having to wrap those methods - i.e.

class S
def +(arg)
S.new(super)
end
end

That’s ugly, and it seems like it was hardly worth inheriting the method
in the first place. [1]

Though perhaps ugly in code, conceptually I don’t think it’s too bad. The
derived class ought to deal with stuff specific to the derived class, not
the base class.

The ‘new’ method which was inherited by S (or at least gives the
appearance of being inherited) doesn’t need a wrapper though: S.new
returns an S, not a String. Perhaps that’s why it’s surprising that the
inherited S#+ returns a String not an S.

I don’t really find it surprising since a sensible default (minimal)
implementation of new can be implicitly defined if it’s not overridden.
It’s never the case that you’d want a subclss’s new to return a superclass
(or other class) instance – the job of new is to return a fresh instance
of the class – so having an implicit one is good. I’d be surprised if any
method that’s not “special” like this would return instances of a subclass,
though.

If you have some sugary way of declaring that a function implicitly “cast”
it’s return result to a subclass (e.g., using some keyword), I think you’d
need to be able to provide some sort of copy constructor/“cast” method from
base to derived class. (This could fallback to the normal constructor, but
that won’t always be able to handle the job.)

···

[1] That doesn’t apply to all inherited methods - e.g. the inherited
[‘<=>’
is perfectly good - just methods which return String in this case

Hi –

···

On Mon, 28 Oct 2002, William Djaja Tjokroaminata wrote:

Brian Candler B.Candler@pobox.com wrote:

The ‘new’ method which was inherited by S (or at least gives the
appearance of being inherited) doesn’t need a wrapper though:
S.new returns an S, not a String. Perhaps that’s why it’s
surprising that the inherited S#+ returns a String not an S.

I agree with everything that you said. I guess in a typed language such
as C++, this is not a problem, because the same data (i.e., bit
patterns) can be interpreted differently based on the type of the variable
that is used to access the data. In a “typeless” language such as Ruby,
on the other hand, the type itself is carried in the data, and therefore I
got this “surprise”.

I personally don’t know which is the “right” way to do OO design. Whereas
a question such as the lack of Boolean parent class in Ruby is
probably more theoretical than practical, a question like this is I think
very practical, because it dictates the whole OO design. I am rather
disappointed actually, because very few (or almost none of the) people
who usually discussed OO-related issues state their opinions. (Or
probably this is just one of the “unsolved problems” in Ruby, along with
others like private variables and block local variables?)

I think it is. See the threads at and around
http://www.ruby-talk.org/21745 and http://www.ruby-talk.org/11381.
I believe it’s all still under consideration by Matz. (Matz?)

David


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

I also find this interesting, as it’s a side-effect of subclassing I hadn’t
thought about.

Somewhere deep in the innards of String#+ it is doing the equivalent of a
String.new; should it be doing a self.class.new instead?

Probably. As a (very) general rule of thumb, if you can avoid a
reference to a hard coded class name, the more flexibility you gain.
Its so easy within in the Foo class to just say “Foo.new”, and most
people do so … with possible problems for derived classes. Saying
“self.class.new” instead of “Foo.new” will avoid the problem you
describe. The problem is retraining class writers (myself included) to
do it the right way.

I agree with everything that you said. I guess in a typed language such
as C++, this is not a problem, because the same data (i.e., bit
patterns) can be interpreted differently based on the type of the variable
that is used to access the data.

It can occur anytime a class makes assumptions about the concrete type
of objects that it creates. There is always the possibility that a
derived class would like a different set of objects created. This
problem has little to do with static vs dynamic typing and can easily
occur in C++ programs.

On a side node (a mild rant) …

In a “typeless” language such as Ruby,

Ruby is hardly “typeless”. It has all kinds of types. Types are a very
important part of programming in Ruby. (end of mild rant)

···

Brian Candler B.Candler@pobox.com wrote:
On Sun, 2002-10-27 at 15:08, William Djaja Tjokroaminata wrote:


– Jim Weirich jweirich@one.net http://w3.one.net/~jweirich

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

Hmm, good point. Or it might have the same arity, but completely different
semantics (just to be perverse).

In one sense, you just want the parent class (String) to do its job and then
coerce the result to the subclass (S). However the subclass may have its own
additional instance variables, and simple coercion would leave them
uninitialised.

Or, you could have a special constructor which takes an object of type
String and turns it into the corresponding object of class S - which in our
example would be a null procedure, but in general might have other things to
do. I think someone suggested a method 'from_parent' to do that. If you had
multiple levels of inheritance then you would have to arrange to call the
whole chain of from_parent's. I'm not sure how to do that cleanly.

I guess what is emerging here is something fundamental but uncomfortable
about the "is_a" relationship: S is_a String, but also S isn't_a String
(because it's an S). Depending on what the implementor of class S has done,
S could be made more and more unlike_a String, to the point where it isn't
much like a String at all.

We know that S has all the instance variables of a String, so that when we
apply the default inherited '+' method, we know the result can set the
corresponding instance variables of S. However S may have other instance
variables, and unless we explicitly call S's constructor, we are not (in the
general case) going to have a valid instance of S.

So I think I understand why the inherited S#+ _has_ to return a String not
an S. It's still not particularly satisfying though :slight_smile:

Regards,

Brian.

···

On Tue, Oct 29, 2002 at 03:30:08AM +0900, George Ogata wrote:

Brian Candler wrote:

> Somewhere deep in the innards of String#+ it is doing the equivalent of a
> String.new; should it be doing a self.class.new instead?

But wouldn't this be a problem if the subclass's constructor had different
access/arity to that of the base class?

Hi Jim,

The problem is retraining class writers (myself included) to
do it the right way.

I don’t think retraining will solve the vast existence of codes that have
been written in the “old” way, including the basic Ruby built-in classes
themselves. That’s why I am very interested whether from OO design point
of view, the current design is “flawed”. (I think OO has been around for
a long time, so it is hard to believe that this kind of problem is not
encountered/solved before.)

This
problem has little to do with static vs dynamic typing and can easily
occur in C++ programs.

Well, it may occur in C++ programs, but it is not the intention. Suppose

derived a;
parent  b;
parent  c;
....
a = b + c;

Assuming that this code compiles and executes, here we are guaranteed that
the class of a is “derived” (i.e., a will respond to methods that
are defined for class derived). There may be some semantic/logic error
depending on the overloadings of the ‘+’ and ‘=’ operators, but that is a
separate issue.

On a side node (a mild rant) …

In a “typeless” language such as Ruby,

Ruby is hardly “typeless”. It has all kinds of types. Types are a very
important part of programming in Ruby. (end of mild rant)

Oh, I agree completely. I just use a terminology that apprently has been
used very often here. I think the term “typed/typeless” is usually
used to refer to the variables themselves, and not the objects.

Regards,

Bill

···

Jim Weirich jweirich@one.net wrote:

dblack@candle.superlink.net wrote:

Or
probably this is just one of the “unsolved problems” in Ruby, along with
others like private variables and block local variables?)

I think it is. See the threads at and around
http://www.ruby-talk.org/21745 and http://www.ruby-talk.org/11381.
I believe it’s all still under consideration by Matz. (Matz?)

Hi David,

Thanks for the pointer. Well, this is really really surprising,
considering that Ruby is not the first OO-based dynamic language (I
think). Because Ruby has “learned” so well from various other languages,
I can only conclude that this is one of the (probably few) unexplored
territories in OO Theory, especially with regard to dynamic languages. I
am wondering how this is done in other OO dynamic languages (any Python
experts?)

Regards,

Bill

The problem is retraining class writers (myself included) to do
it the right way.
I don’t think retraining will solve the vast existence of codes
that have been written in the “old” way, including the basic Ruby
built-in classes themselves. That’s why I am very interested
whether from OO design point of view, the current design is
“flawed”. (I think OO has been around for a long time, so it is
hard to believe that this kind of problem is not
encountered/solved before.)

I think it is flawed. Personally.

This problem has little to do with static vs dynamic typing and
can easily occur in C++ programs.

Well, it may occur in C++ programs, but it is not the intention.
Suppose

derived a;
parent b;
parent c;

a = b + c;

Assuming that this code compiles and executes, here we are
guaranteed that the class of a is “derived” (i.e., a will respond
to methods that are defined for class derived). There may be some
semantic/logic error depending on the overloadings of the ‘+’ and
‘=’ operators, but that is a separate issue.

This is where Ruby’s typeless variables (not typeless objects)
causes problems. In the compiled language, the variable ‘a’ has a
distinct type. With respect to your example, I would expect that
‘a’ would take on the type of Parent in Ruby. What I don’t expect,
however, is for:

a = a + b

to take on the type of Parent. After all, we’re really doing:

a = a.+(b)

So the typeness of a should be carried, even though it’s the
Parent’s operator which is called. It’s rather like the operator had
been declared without ‘virtual’ in C++.

Matters are made rather worse because there’s no clear way of doing
typecasting (yes, there is ‘coerce’, but that’s not really
typecasting) of objects. Additionally, because the variables
themselves are typeless, doing:

a = b + a               # a = b.+(a)

Will result in a being a reference to a Parent, even though in C++,
the result would remain a Derived because types are associated with
variables. Jim’s solution (self.class.new) works quite well for the
first case (a += b), but it works not at all for the second case (a
= b + a). It’s correct, and it’s consistent, but it still feels
wrong.

(There’s a point where, at least IMO, if you’re dealing with Parent
and Derived and only those two classes are involved, then the
results should be coerced into Derived. This, however, results in
problems if you have DerivedA and DerivedB, both children of Parent.
Which class should then be used as the result?)

It’s not an easy problem. Jim’s solution is a decent one, and it
might be that some syntactic sugar could be provided. If I do:

class Foo
  def bar
    Foo.new
  end
end

it could be interpreted as:

class Foo
  def bar
    self.class.new
  end
end

because we are in the context of “class Foo”. I’m not sure if this
would be a good idea or not, but it would at least make Jim’s
solution ‘automatic.’

-austin
– Austin Ziegler, austin@halostatue.ca on 2002.10.28 at 09.56.17

···

On Mon, 28 Oct 2002 23:49:39 +0900, William Djaja Tjokroaminata wrote:

Jim Weirich jweirich@one.net wrote:

bill-

Well, it may occur in C++ programs, but it is not the intention. Suppose

derived a;
parent  b;
parent  c;
....
a = b + c;

Assuming that this code compiles and executes, here we are guaranteed that
the class of a is “derived” (i.e., a will respond to methods that
are defined for class derived). There may be some semantic/logic error
depending on the overloadings of the ‘+’ and ‘=’ operators, but that is a
separate issue.

i would say it occurs all the time in c++ programs, it’s as easy as :

derived *a;
parent *b;
parent *c;

further_derived *z;

a = b + c;

all we are guarenteed of, is that ‘a’ will point to an a, or some subclass of
a, like further_derived, - this knowledge is not available (by inquiry) to use
at compile time, nor at runtime. i think this a more accurate example since
the pointer is really the only type to use if one wants to consider all of
c++'s object oriented (mis) features…

furthermore ( opinions were solicited earlier right? :wink: ) i would say this type of
coding is not ‘good’ object oriented coding since, in order to create operator
‘+’ for the parent class, knowledge of it’s descendants was required. we have
alot of code like this in our shop and it’s terrible to work with.
consider that the header files for the parent class must include the header
file for the derived class, which must include the header file for the parent
class, which must include the header file for the derived class, which must
incl… (recurse here untill you get sick of it)

it’s header file madness. only the preprocessor saves the day.

you even have to maniplulate the build order since there are circular object
dependancies - ouch.

if this doesn’t make sense to anyone - try writing this yourself

class parent;
class child;

child parent::operator + (parent anOther);

when splitting the files out into *.h, *.cc files

on a more general note, though many will object, i think subclassing itself
often (always?) violates encapsulation and so it not good object oriented
coding… wait a minute isn’t inheritence supposed to be a ‘feature’ of object
oriented coding? i guess the point is that sub-classing usually means that
a subclass has intimate knowledge of the guts of it’s parent(s) and that can
lead to trouble (as per the examples in this thread). i have found that,
except in rare cases when coded by very clever programmers, subclassing almost
always introduces subtle bugs, or at least inconsistencies. this does’t mean
it useless - it’s just about 47 time more difficult than simply

class Foo < AnOtherClass

my rule is this :

use Has-A before Is-A whenever possible, when using Is-A – think long and
hard about it!!

-ara

···

On Mon, 28 Oct 2002, William Djaja Tjokroaminata 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
====================================

Well, it may occur in C++ programs, but it is not the intention. Suppose

derived a;
parent  b;
parent  c;
....
a = b + c;

Assuming that this code compiles and executes, here we are guaranteed that
the class of a is “derived” (i.e., a will respond to methods that
are defined for class derived).

Well, yes … but this is doing something completely different than the
Ruby example. b and c are added together (for some definition of “+”)
and the result is a Parent type. The parent is then converted to the
derived type (either by an appropriate constructor or assignment
operator in Derived).

The same effect can be achieved in Ruby with …

b = Parent.new
c = Parent.new
a = Derived.from_parent(b+c)

Here “from_parent” performs the same function as the CTOR/Assignment
statement in C++.

However, the original question was slightly different in that it had
either b or c being objects of the derived type and dynamically
determining the proper return type.

There may be some semantic/logic error
depending on the overloadings of the ‘+’ and ‘=’ operators, but that is a
separate issue.

Right… to get the proper behavior in C++, you must explicitly program
for it. Likewise in Ruby.

In a “typeless” language such as Ruby,

Ruby is hardly “typeless”. It has all kinds of types. Types are a very
important part of programming in Ruby. (end of mild rant)

Oh, I agree completely. I just use a terminology that apprently has been
used very often here. I think the term “typed/typeless” is usually
used to refer to the variables themselves, and not the objects.

I don’t mind the “typeless” modifier being applied to variables. I was
objecting to it being applied to the language. :slight_smile:

···

On Mon, 2002-10-28 at 09:49, William Djaja Tjokroaminata wrote:


– Jim Weirich jweirich@one.net http://w3.one.net/~jweirich

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

Hi Ara,

furthermore ( opinions were solicited earlier right? :wink: ) i would say this type of
coding is not ‘good’ object oriented coding since, in order to create operator
‘+’ for the parent class, knowledge of it’s descendants was required. we have
alot of code like this in our shop and it’s terrible to work with.
consider that the header files for the parent class must include the header
file for the derived class, which must include the header file for the parent
class, which must include the header file for the derived class, which must
incl… (recurse here untill you get sick of it)

it’s header file madness. only the preprocessor saves the day.

you even have to maniplulate the build order since there are circular object
dependancies - ouch.

if this doesn’t make sense to anyone - try writing this yourself

class parent;
class child;

child parent::operator + (parent anOther);

when splitting the files out into *.h, *.cc files

I agree with what you said. I also have been thinking of using “copy
constructors” in Ruby, but either going from parent to child or from child
to parent, it is really messy. Besides, it seems that by default Ruby
does not like deep copy.

my rule is this :

use Has-A before Is-A whenever possible, when using Is-A – think long and
hard about it!!

Mmmm… as I don’t know deep OO theory, I don’t know what to say. I think
on the discussions on contract/interface, there are people who advocate to
use Is-A instead of Has-A.

Regards,

Bill

···

ahoward ahoward@fsl.noaa.gov wrote:

This is where Ruby’s typeless variables (not typeless objects)
causes problems. In the compiled language, the variable ‘a’ has a
distinct type. With respect to your example, I would expect that
‘a’ would take on the type of Parent in Ruby. What I don’t expect,
however, is for:

a = a + b

to take on the type of Parent. After all, we’re really doing:

a = a.+(b)

So the typeness of a should be carried, even though it’s the
Parent’s operator which is called. It’s rather like the operator had
been declared without ‘virtual’ in C++.

Very well said, Austin, very well said.

It’s not an easy problem. Jim’s solution is a decent one, and it
might be that some syntactic sugar could be provided.

Although I don’t know the extent of the consequences of doing
“self.class.something” in the classes, it looks like a good idea to
me too. Whether it is automatic or manual, probably it is
secondary (it is like, as you said, having the ‘virtual’ keyword in
C++, whereas in Java every function is virtual). I am curious in knowing
Matz’s thought currently, whether he even thinks that this is indeed a
problem.

Regards,

Bill

···

Austin Ziegler austin@halostatue.ca wrote: