What's so special about operators, built-in classes and modules?

N

Nikolai Weibull

Ara.T.Howard said:
This message is in MIME format. The first part should be readable
text, while the remaining parts are likely unreadable without
MIME-aware tools.

^--- Why are you doing this?

Works fine on my end. Thank you for making my reading experience that
much more pleasurable.
like this
=20
.[0m~@~Xfoo.[0m~0~X .[0m~@~\bar.[0m~@~]

Looks more like a Lisp (format) string than ANSI coloring escapes, but
the [0m is certainly suspicious ;-),
nikolai

--=20
Nikolai Weibull: now available free of charge at http://bitwi.se/!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}
 
A

Ara.T.Howard

And how is that confusing? It's exactly what currently
happens when you include multiple modules.

module A ; end
module B ; end

class C
include A
include B
end

C.new.is_a? A #=> true
C.new.is_a? B #=> true


I don't see how this could ever make sense.


The version that doesn't have B.include(A) imply b.is_a?(A)
does seem broken and confusing, but is a straw man.

straw man! i'm not that smart ;-)

i was doing too much at once. all i was trying to say was that

B < A

means inheritence. if you also want to be able to

class B
include A
include Z
end

and have that also mean inheritecne - then multiple inheritence must be
addressed. my point is simply that i don't think you can unify modules and
classes without also intrducing multiple inheritence - which is what matz's
comment about complex graphs was getting at... (i think)

you can't currently do this

http://en.wikipedia.org/wiki/Diamond_problem

with mixins. if unification took place you could.
If anything I said in this thread was out of ignorance, I
apologize for my arrogance. However, I would appreciate it
if you would point any such errors out.

i didn't mean you - but people learning ruby. improved docs could benefit
them. sorry for confusion.
But inheritance would work exactly the same as it does now.


How is multiple inheritance far less powerful than mixins?

because people don't use it well - it's complexity precludes average
programers using it in the very situations where it could be most benefit..
just at it's prevelance in languages which support i and compare that to the
useage of mixins in ruby, for example.

mixins are powerful because they provide 90% of the functionality of mi with
10% of the debugging. this is primarily because it's easy to affect the
method search tree.

interesting:

http://64.233.167.104/search?q=cach...Track.pdf+mixin+vs+multiple+inheritence&hl=en

cheers.

-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| My religion is very simple. My religion is kindness.
| --Tenzin Gyatso
===============================================================================
 
D

Daniel Brockman

Ara.T.Howard said:
i'd say __all__ code depends on that. otherwise

module M
def self::new
raise
end
end
class C
include M
end

c =3D C::new

Surely you are not suggesting that all code defines
singleton =E2=80=98new=E2=80=99 methods on modules?

Considering that this doesn't work,

class X
def self.new
raise
end
end

class Y < X
end

x =3D X.new

why do you expect your example to work?

I don't get why Y's singleton class inherits from X's,
while C's *doesn't* inherit from M's.
i'd imagine this is the (one of) reason(s) for the
current behaviour.

Why are you defining M.new? Do you have actual code that
does this?
yes - i just am not seeing how it could be done in a way
that preserved or added to current functionality and was
simpler.

No, it would not be possible to retain full backwards
compatibility, but I cannot think of a real-world case in
which actual problems would result.
inheritence needs to be addressed specifically for it to
make sense.

Why do you say that?
How does this look?

=E2=80=98foo=E2=80=99 =E2=80=9Cbar=E2=80=9D

like this

.[0m~@~Xfoo.[0m~0~X .[0m~@~\bar.[0m~@~]

Out of curiosity, what mail reader do you use?

--=20
Daniel Brockman <[email protected]>
 
D

Daniel Brockman

Ara.T.Howard said:
i was doing too much at once. all i was trying to say
was that

B < A

means inheritence. if you also want to be able to

class B
include A
include Z
end

and have that also mean inheritecne - then multiple
inheritence must be addressed.

In what way must anything new be addressed?
my point is simply that i don't think you can unify
modules and classes without also intrducing multiple
inheritence

Of course not. Indeed, many people consider Ruby's mixins
to already be a form of MI.
you can't currently do this

http://en.wikipedia.org/wiki/Diamond_problem

with mixins.

Here we go again...

module A
def foo(bar) puts(bar) end
end

mobule B
include A
def foo ; super(123) end
end

module C
include A
def foo ; super(456) end
end

class D
include B
include C
end
if unification took place you could.

Indeed, you still could.
because people don't use it well -

Even if that were proved true, it still wouldn't imply that
multiple inheritance is =E2=80=9Cfar less powerful=E2=80=9D than mixins.
it's complexity precludes average programers using it in
the very situations where it could be most benefit..

What alleged complexity are you talking about?

Is it simply that there would be no concept of superclass,
and hence no way to automatically draw an inheritance tree?

Unifying modules and classes will not force you to inherit
from String, Integer, Hash and IO at the same time.

You could still do everything you do now, with no
added complexity.
just at it's prevelance in languages which support i and
compare that to the useage of mixins in ruby, for example.

If you see a way to make a useful comparison, please do.
mixins are powerful because they provide 90% of the
functionality of mi
Agreed.

with 10% of the debugging.

That, however, is a completely unsubstantiated and IMHO
outrageous claim. (Maybe I should counter it by claiming
that MI is powerful because it provides 110% of the
functionality of mixins, with only 10% of the debugging.)
this is primarily because it's easy to affect the method
search tree.

I don't understand this. What do you mean?

--=20
Daniel Brockman <[email protected]>
 
A

Ara.T.Howard

--8323328-435739242-1122561336=:14494
Content-Type: MULTIPART/MIXED; BOUNDARY="8323328-435739242-1122561336=:14494"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

--8323328-435739242-1122561336=:14494
Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE

Surely you are not suggesting that all code defines
singleton =E2=80=98new=E2=80=99 methods on modules?

Considering that this doesn't work,

class X
def self.new
raise
end
end

class Y < X
end

x =3D X.new

why do you expect your example to work?

well - you have to actually __use__ the method - i was pointing to the fact
that they are inherited in the case of subclasses and are not in the case o=
f
mixins ;-)

harp:~ > cat a.rb
class X
def self.new
raise
end
end

class Y < X
def self.new; super; end
end

x =3D X.new

harp:~ > ruby a.rb
a.rb:3:in `new': unhandled exception
from a.rb:11

I don't get why Y's singleton class inherits from X's,
while C's *doesn't* inherit from M's.

because otherwise including module could clobber class methods which genera=
lly
include hooks to create instances like 'new', 'instance', 'parse', etc. if=
you
replace the set of methods responsible for stamping out instances you are n=
ot
'mixing-in' functionality to those instances - but changing what type those
will be. there is a fundemental difference here.
Why are you defining M.new? Do you have actual code that > does this?

tons. just yesterday i was writing a parser. all the code is wrapped in a
module to protect namespaces. each line of the file i am parsing is a comm=
and
sent to a satelite. i have a factory which produced command objects of a
given type that's arranged like

module Command
class Abstract
...
end
class Load < Abstract
...
end
class Sub < Abstract
...
end
class Add < Abstract
...
end
class Store < Abstract
...
end
def self::new line
orbit_normal_time, command, register, value =3D parse line
klass =3D
case command
when /load/
Load
when /sub/
Sub
when /add/
Add
when /store/
Store
end
klass::new(orbit_normal_time, register, value)
end
end

however, i actually use this class in another like

class PayloadActivationMessage < AbstractMessage
include Command
end

and this would change the notion of calling 'super' if what you are suggest=
ing
were true. eg - if 'some_method' were defined as a class method in
PayloadActivationMessage, AbstractMessage, and Command, then a definition l=
ike

def PayloadActivationMessage::some_method
super + 42
end

would seem to call AbstractMessage::some_method (due to inheritence) but wo=
uld
actually call Command::some_method if class methods were automatically pull=
ed
in by 'include' statements. there are cases where you want this and that's
what 'append_features' is for - but to have this for the normal case would =
be
quite suprising for most applications i think. not to mention changing the
notion of super is, be definition, a very strong form on inheritence.
No, it would not be possible to retain full backwards compatibility, but = I
cannot think of a real-world case in which actual problems would result.

added multiple inheritence semantics for module inclusion would not be
backwards compatibile imho.
Why do you say that?

well - because that's what you are suggesting!?


pine, mutt, or mail.

but even the web interface shows the problem:

http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-talk/149703

look at the line with 'const char' on it.

cheers.

-a
--=20
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| My religion is very simple. My religion is kindness.
| --Tenzin Gyatso
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D

--8323328-435739242-1122561336=:14494--
--8323328-435739242-1122561336=:14494--
 
T

Trans

Ara.T.Howard said:
because otherwise including module could clobber class methods which generally
include hooks to create instances like 'new', 'instance', 'parse', etc. if you
replace the set of methods responsible for stamping out instances you are not
'mixing-in' functionality to those instances - but changing what type those
will be. there is a fundemental difference here.

That assumes no other way to deal with this "clobbering" is utilized. I
think your overstating to say there is a fundemental difference. It
still boils down to the "Duck" --walk, talk and all that.
added multiple inheritence semantics for module inclusion would not be
backwards compatibile imho.

What would break? BTW I think that handling this kind of "MI" would be
fairly straight forward with ancestor directed calls (eg.
AModule\amethod)

2c,

T.
 
A

Ara.T.Howard

That assumes no other way to deal with this "clobbering" is utilized. I
think your overstating to say there is a fundemental difference. It
still boils down to the "Duck" --walk, talk and all that.

i'm not sure i agree - so long as ruby has types/classes/whatever returning a
different kind of one sure seems alot different than returning a specialzation
(subclass) of one. however 'type' is pretty muddy in ruby as we all agree.
What would break?

i've given some examples in this thread from my own code... i assume there
would be more.
BTW I think that handling this kind of "MI" would be fairly straight forward
with ancestor directed calls (eg. AModule\amethod)

sure - it could be done. but only by matz.

cheers.

-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| My religion is very simple. My religion is kindness.
| --Tenzin Gyatso
===============================================================================
 
D

Daniel Brockman

Thank you for keeping up Ara --- I'm enjoying this
discussion. :)


What I meant by this was that your claim, "i'd say __all__
code depends on that," was a bit bold.
well - you have to actually __use__ the method - i was
pointing to the fact that they are inherited in the case
of subclasses and are not in the case of mixins ;-)

Yes, and I was trying to ask you whether or not and *why*
you expect such a difference in behavior. (If you didn't
expect it, then you agree it is surprising?)
harp:~ > cat a.rb
class X
def self.new
raise
end
end

class Y < X
def self.new; super; end
end

x =3D X.new

harp:~ > ruby a.rb
a.rb:3:in `new': unhandled exception
from a.rb:11



because otherwise including module could clobber class
methods which generally include hooks to create instances
like 'new', 'instance', 'parse', etc.

But you have already demonstrated that inheriting from a
class *can* clobber methods like Class#new. So I don't see
the difference. I know *what* happens; just not *why*.

class AbstractFoo
def self.new
raise "nope!"
end
end

class Foo < AbstractFoo
end

foo =3D Foo.new # error

class Foo
def self.new
# What do I put here?
end
end

Clearly this problem already exists for class inheritance.
if you replace the set of methods responsible for stamping
out instances you are not 'mixing-in' functionality to
those instances -

(No, you are mixing in functionality to the *class*, not the
instances, though of course the latter refer to the former.)
but changing what type those will be. there is a
fundemental difference here.

You are making a *classic* bifurcation here: Your argument
boils down to, "you are changing what type the instances
will have, therefore you are not mixing in functionality,"
when in fact I am doing both.

It's like if I were to say that in your example,
class X
def self.new
raise
end
end

class Y < X
def self.new; super; end
end

the Y class is not inheriting from the X class, because it's
preventing instances from being created.
Why are you defining M.new? Do you have actual code that
does this?

tons. [...]

module Command
class Abstract
...
end
class Load < Abstract
...
end
class Sub < Abstract
...
end
class Add < Abstract
...
end
class Store < Abstract
...
end
def self::new line
orbit_normal_time, command, register, value =3D parse line
klass =3D
case command
when /load/
Load
when /sub/
Sub
when /add/
Add
when /store/
Store
end
klass::new(orbit_normal_time, register, value)
end
end
=20
class PayloadActivationMessage < AbstractMessage
include Command
end

Okay, thank you. I can see that a lot of similar code
probably exists. But the example you've given would not be
difficult to fix if module metaclass inheritance were added.

Actually, your code seems pretty fishy to me as it is:

command =3D Command.new(foo)
command.is_a? Command #=3D> false

I think it would have been a better idea to do this:

class Command
class Load < Command
...
end
class Sub < Command
...
end
class Add < Command
...
end
class Store < Command
...
end
def self::new line
orbit_normal_time, command, register, value =3D parse line
klass =3D
case command
when /load/
Load
when /sub/
Sub
when /add/
Add
when /store/
Store
end
klass::new(orbit_normal_time, register, value)
end
end

If you change your code in this way, the problem disappears;
in other words, your code is no longer an example of where
module metaclass inheritance is a problem.

It's useful to see actual code that would break, but it
would be even more useful to see actual, *non-fishy* code
that would break. So could you share any other examples?
changing the notion of super is, be definition, a very
strong form on inheritence.

Then it is your opinion that including a module is a "very
strong form of inheritence"?
added multiple inheritence semantics for module inclusion
would not be backwards compatibile imho.

What are "multiple inheritence semantics"?

--=20
Daniel Brockman <[email protected]>
 
B

Ben Giddings

this is a similar 'argument':

in c most people think that a definition like

int foobar (const char * string);

will prevent people from modifiying string. it won't. for that
one needs

int foobar (const char * const string);

why not unify them?

the answer is obvious: because they are differnet. a focus on
clarifying
doccumentation might be wiser in this case. and, in the end,
certain people
are simply going to have to be told to rtfm - not everything can be
intuitive
AND powerful.

Actually, the first example will prevent people from modifying the
string, at least directly. Adding the second const only prevents
them from reassigning the "string" variable within the function.

The biggest problem here is that in C strings don't exist. People go
to great lengths to pretend that they do, but really, they don't.
There are only arrays of characters terminated by a null character.
If people would quit believing that strings actually exist, then the
problems with strings and C would go away.

What makes the problem worse is that C makes it really easy to
believe that strings exist. Having constructs like "Hello World!\n"
makes people think that there is such a thing as a string, but the
compiler sees that as being identical to {'H', 'e', 'l', 'l', 'o', '
', 'W', 'o', 'r', 'l', 'd', '!', '\n', '\0'}.

Now you could argue that strings actually *do* exist, and that they
*are* arrays of characters terminated by a null. I don't buy it
though. Why not? Because *anything* can be a string of characters
terminated by a null. C may be statically typed, but try declaring
an array of characters and then calling strlen(the_array). It may
give you a length, or maybe a segfault, but it will never say "hey!
that's not a string!"

Aside from the issue of C strings, I'd say the way const is used in
functions is b0rken in C. Take int foo(const int bar); Since bar is
passed by value, any modifications of it in the body of the function
are only local to the function. In my experience good C coders treat
every parameter passed by value as "const", otherwise they lose a
record of what parameters the function was supplied. Because of
this, "const" is only really useful when applied to pointers. And
the syntax for that is really confusing -- generally the syntax for
pointers is really confusing in C as a general rule. The concept of
a pointer is pretty simple -- it's an address in memory, the only
thing that makes it difficult is the syntax.

In this bit of code, you can change the variable a, which is a
pointer, making it point at something else, but you can't change the
value it points at. As for b, you can change the value it points at,
but you can't change the variable itself.

int bar(const int *a, int *const b, const int c)
{
int d, e;
//*a = 3;
*b = 4;
a = &d;
//b = &e;
//c = 5;
}

The "const char* string" works the same way, preventing you from
modifying the contents of the string, but letting you reassign the
variable. The way to read it (I believe) is "if you dereference
'string' you will get a constant character".

Anyhow, bringing this back to Ruby...

I think Modules and Classes should be separate, but I think there's a
lot of confusion there.

Classes are pretty straightforward, but modules are not. I'd say
most of the confusion comes from the fact that modules can either be
groups of functions that are mixed in to other things, or they can be
namespaces. That dual use gets confusing. Oh, and it's also
confusing that a Class is a Module in the inheritance tree.

I agree that it's confusing that including a module doesn't hide
functions that a class defines on its own. IMHO it isn't clear that
"include FooModule" is similar to inheritance. It looks like it's
similar to "attr_accessor", not like class Foo < Bar.

Adding documentation would help a bit with this issue, but it doesn't
seem like the ideal approach to me. Instead of documenting a
confusing issue, why not understand why it's confusing and fix it?

I'd suggest that for one thing, modules-as-namespaces should
disappear, there should simply be a "namespace" keyword so "Math::pI"
is in the Math namespace, not the Math module. Then, I'd say "mixin"
instead of "module". Finally to address the issue of it not
overriding methods that already exist, maybe a second parameter to
"include" named "override" that defaults to false? Sure, that could
break things when you mix something in that clobbers a "helper
method", but just having that option there makes people realize that
it doesn't always override things.

As for multiple inheritance vs. single inheritance, I think the
problem isn't a technical one, it's a human one. As Adam P Jenkins
pointed out:

By your logic, C++ and Python don't have the diamond problem
either. Both
of those languages have well defined ways in which the method to
call is
chosen, which have to do with the order in which the programmer
writes things.

So the question becomes "What is going to provide the most
flexibility with the least confusion?" I think that rules out
multiple inheritance. Ruby is a really flexible language. Even
without resorting to "eval" you can do some pretty astounding
things. But in general the approach seems to be "unless you're
trying to do something tricky, things generally behave as they
should". I would say that having multiple inheritance adds a lot of
potential for confusion without a lot of benefit. Crafty programmers
can get all(?) the benefits of MI from Ruby today, as long as they're
willing to be sneaky about it. Less crafty programmers don't have to
worry about the diamond problem. Doesn't that seem like the way
things should be?

Ben
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top