function overloading 
Author Message
 function overloading

C++ allows function overloading like:

void func( int x, int y ) { /* ... */ }
void func( int x ) { /* ... */ }

but this in ISE Eiffel and SmallEiffel cause errors, so I assume it's
not allowed in the Eiffel language

func( x, y: INTEGER ) is do end
func( x: INTEGER ) is do end

why does the language not permit function overloading?

fysx



Wed, 31 Oct 2001 03:00:00 GMT  
 function overloading

Quote:

> C++ allows function overloading like:
> void func( int x, int y ) { /* ... */ }
> void func( int x ) { /* ... */ }
> but this in ISE Eiffel and SmallEiffel cause errors, so I assume it's
> not allowed in the Eiffel language

Nope, that type of overloading, which BM refers to as "syntactic
overloading" is not allowed in Eiffel.

Quote:
> func( x, y: INTEGER ) is do end
> func( x: INTEGER ) is do end
> why does the language not permit function overloading?

To start with, Eiffel does allow what is called "semantic overloading",
where a function name has different meaning depending on the target
of the call. Such as:

array.put ('a',3)
stack.put ('a')

However, Eiffel does not provide for overloading based on the arguments
of the call, as you've illustrated above. Why are they not included?
Well principally because they introduce extra complexity, but do not
allow you to actually do anything that you could not do without them.

Consider the nature of overloading in C++/Java. In neither case will
the system use the type information dynamically to dispatch (languages
such as the OO forms of Lisp will perform "multiple dispatch" like
this), so the compiler must figure out strictly from the static types
of your arguments which feature to call. When combined with subtyping
through inheritance, this can lead to contradictory situations, where
the compiler can't decide from the arguments which to call. Also,
sometimes it might make a decision based on its complex algorithm to
call a feature different from the one the programmer commonsensically
thought it would. Since these are compile time decisions, you loose
no expressive power by giving the features distinct names and calling
them explicitly. Here there is no possibility of confusion. Eiffel
goes as far as to make this a principle of the language: using the
text of the name as the sole identifier of a feature within a class.
If you inherit two features with the same name, the situation must
either be resolved through one or more renamings, or the features
must somehow be joined or merged.

As a side note: it's nice to see newcomers attracted to Eiffel, and
you're certainly working hard to learn it. Have you considered tracking
down these books:

 Eiffel The Language

 Object Oriented Software Construction 2

Both by Bertrand Meyer. They are, more or less, the bibles of Eiffel,
and will cover most all of the questions you might have. Alas, they
do carry a hefty price tag (OOSC2 or grocery money being a tough choice).

Happy coding

--
--Jeffrey Straszheim
---Systems Engineer, Programmer
----stimuli AT shadow DOT net



Wed, 31 Oct 2001 03:00:00 GMT  
 function overloading

Quote:
> C++ allows function overloading like:

> void func( int x, int y ) { /* ... */ }
> void func( int x ) { /* ... */ }

> but this in ISE Eiffel and SmallEiffel cause errors, so I assume it's
> not allowed in the Eiffel language

> func( x, y: INTEGER ) is do end
> func( x: INTEGER ) is do end

> why does the language not permit function overloading?

Because it is considered evil. In complex programs it is not easy to tell
what function is beeing called. In Eiffel it is considered good style to
give features (thats what in C++ woud be the name of the set {function,
variable}) names that indicate exactly what the stands for. The number of
keystrokes is not that important, when you consider the fact that (good!)
source is read much more often than it is written.

The book "Object Oriented Software Constructon 2" (by Bertrand Meyer /
Prentice Hall) offers you in depth discussions about this topic and a lot
of others too. If you are serious with Software Engeneering this is a
must read. Even if you do not plan to program in Eiffel.

hope this helps,
Andreas



Wed, 31 Oct 2001 03:00:00 GMT  
 function overloading

Thanks for the info

Quote:

> As a side note: it's nice to see newcomers attracted to Eiffel, and
> you're certainly working hard to learn it. Have you considered tracking
> down these books:

>  Eiffel The Language

>  Object Oriented Software Construction 2

> Both by Bertrand Meyer. They are, more or less, the bibles of Eiffel,
> and will cover most all of the questions you might have. Alas, they
> do carry a hefty price tag (OOSC2 or grocery money being a tough choice).

Both of them are currently in the mail hurtling towards my mailbox where I
will sit upon the couch and digest them.  I'm sure I'll spam this newsgroup
tons with questions while I read them.

fysx



Wed, 31 Oct 2001 03:00:00 GMT  
 function overloading

Quote:

>> why does the language not permit function overloading?

>Because it is considered evil. In complex programs it is not easy to tell
>what function is beeing called. In Eiffel it is considered good style to
>give features (thats what in C++ woud be the name of the set {function,
>variable}) names that indicate exactly what the stands for. The number of
>keystrokes is not that important, when you consider the fact that (good!)
>source is read much more often than it is written.

When you argue against counting the keystrokes, you're
missing the whole point of overloading.  It has nothing to
do with keystrokes.  The function name has a meaning at
a higher level of abstraction than the argument types.  When
you encode some of the argument types in the function name,
you lower the level of abstraction at which you think about
that function call.  The lower your level of abstraction,
the more likely you are to get bogged down in details.  The
higher your level of abstraction, the more likely you are
to get the kind of insight that leads to creating better
solutions to the application problems.  Thus overloading
can free your mind to be more creative.


Thu, 01 Nov 2001 03:00:00 GMT  
 function overloading

<snip>

Quote:
> When you argue against counting the keystrokes, you're
> missing the whole point of overloading.  It has nothing to
> do with keystrokes.  The function name has a meaning at
> a higher level of abstraction than the argument types.  When
> you encode some of the argument types in the function name,
> you lower the level of abstraction at which you think about
> that function call.  The lower your level of abstraction,
> the more likely you are to get bogged down in details.  The
> higher your level of abstraction, the more likely you are
> to get the kind of insight that leads to creating better
> solutions to the application problems.  Thus overloading
> can free your mind to be more creative.

The argument against syntactic overloading has nothing to do
with keystroke count. Consider this situation:

class STACK_THAT_CAN_HOLD_A_OR_B

 ...

feature -- add items

  put (c: A) is
    ....

  put (c: B) is
   ....

 ...

end -- clas STACK_THAT_CAN_HOLD_A_OR_B

So here we have classic C++/Java style overloading. Note that this differs
from the perfectly allowed symantic overloading: e.g. when a STACK[G] has
an feature put (e: G) and a QUEUE[G] has a corresponding feature put (e: G),
both with the same name but different behvior. Let's back to the example,
say I create some class:

class E

inherit

  A, B

 ....

end -- class E

And I'd like to add it to my STACK_THAT_CAN_HOLD_A_OR_B. Certainly I should
be allowed (after all, it is not a STACK_THAT_CAN_HOLD_A_XOR_B), but how
can I? Which version of 'put' should the compiler choose?

In this specific case, I need to give the features distinct names:
put_a (c: A) and put_b (c: B) are likely choices. Have I gotten
"bogged down in details" here? I don't think so. No more than remembering
that 'put' needs an index for an ARRAY[G] but not for a STACK[G].

--
--Jeffrey Straszheim
---Systems Engineer, Programmer
----stimuli AT shadow DOT net



Thu, 01 Nov 2001 03:00:00 GMT  
 function overloading
On Sun, 16 May 1999 07:51:56 -0400, Jeffrey L Straszheim

Quote:

>And I'd like to add it to my STACK_THAT_CAN_HOLD_A_OR_B. Certainly I should
>be allowed (after all, it is not a STACK_THAT_CAN_HOLD_A_XOR_B), but how
>can I? Which version of 'put' should the compiler choose?

You have to get rid of the ambiguity, or you will get a
compiler error.  Simply define put in your new class.
It can invoke either of them.  The whole thing is
trivial.  A good compiler will tell you exactly what is
wrong and why it's ambiguous.  It's a one-minute
solution, and it works perfectly, without making any
kind of mess.

Quote:
>In this specific case, I need to give the features distinct names:
>put_a (c: A) and put_b (c: B) are likely choices. Have I gotten

That's a slightly messy solution to a problem that
doesn't exist.  In a more complicated example,
it could be a lot messier, but the problem it solves
still wouldn't exist.

Quote:
>"bogged down in details" here? I don't think so. No more than remembering
>that 'put' needs an index for an ARRAY[G] but not for a STACK[G].

A simple example is not good for showing how you can
get bogged down in details.  It happens when you work
with real code in sophisticated applications.

In any case, STACK_THAT_CAN_HOLD is horrible
naming and factoring.  What goes in the stack should
be of one class.  The different things it can hold should
be subclasses of that one class.  Of course that has
nothing to do with this argument, but it does show that
your example, besides not providing the evidence you
think it does, is horribly contrived.

The reason why this kind of argument has to be an
abstract argument is because the examples that show
you getting bogged down in the details would cause the
argument to get bogged down even more.



Thu, 01 Nov 2001 03:00:00 GMT  
 function overloading

Quote:

> On Sun, 16 May 1999 07:51:56 -0400, Jeffrey L Straszheim

> >And I'd like to add it to my STACK_THAT_CAN_HOLD_A_OR_B. Certainly I should
> >be allowed (after all, it is not a STACK_THAT_CAN_HOLD_A_XOR_B), but how
> >can I? Which version of 'put' should the compiler choose?

> You have to get rid of the ambiguity, or you will get a
> compiler error.  Simply define put in your new class.
> It can invoke either of them.  The whole thing is
> trivial.  A good compiler will tell you exactly what is
> wrong and why it's ambiguous.  It's a one-minute
> solution, and it works perfectly, without making any
> kind of mess.

But that's exactly the point. How does one get rid of the
ambiguity? Please show the exact syntax. Sure the compiler
will notice the problem. How does the programmer specify
which routine should be used? I have a class that has a
routine 'put' that responds differently for A's and for
B's. If I have an object that is both and A and a B, what
should I do? Rewrite the STACK_THAT_CONTAINS... class? But
that's exactly what I'd like to avoid. The class should
work as is. With distinct names, I have no problem.

Quote:
> >In this specific case, I need to give the features distinct names:
> >put_a (c: A) and put_b (c: B) are likely choices. Have I gotten

> That's a slightly messy solution to a problem that
> doesn't exist.  In a more complicated example,
> it could be a lot messier, but the problem it solves
> still wouldn't exist.

The problem does exist. The compiler can't decide which feature
to call. There does not exist a mechanism to specify which,
because we've relied on the compiler to do so. In Eiffel, we
just give the features distinct names. Doing that leaves
no problem.

Quote:
> A simple example is not good for showing how you can
> get bogged down in details.  It happens when you work
> with real code in sophisticated applications.

I'll keep this in mind next time I work with real code in
a sophisticated application.

Quote:
> In any case, STACK_THAT_CAN_HOLD is horrible
> naming and factoring.  What goes in the stack should
> be of one class.  The different things it can hold should
> be subclasses of that one class.  Of course that has
> nothing to do with this argument, but it does show that
> your example, besides not providing the evidence you
> think it does, is horribly contrived.

It is contrived, but it is merely illustrative. Do you really
wish to belabor that point?

Consider this: if you've chosen to use syntactic overloading,
clearly you wish to have features with a common name, but with
behavior that depends on the type of the arguments. Yet, you cannot
guarantee that the compiler can always decide which feature to
call. C++ solves this problem, but only with ugly casts and the
like. Eiffel doesn't do things that way. Now, are you suggesting
a specific change to the language? You'd have to.

Quote:
> The reason why this kind of argument has to be an
> abstract argument is because the examples that show
> you getting bogged down in the details would cause the
> argument to get bogged down even more.

--
--Jeffrey Straszheim
---Systems Engineer, Programmer
----stimuli AT shadow DOT net


Thu, 01 Nov 2001 03:00:00 GMT  
 function overloading
On Sun, 16 May 1999 23:34:53 -0400, Jeffrey L Straszheim

[Argument against syntactic function overloading deleted]

The basic problem is that you're confusing function
overloading with container type overloading.  A stack
should contain one type of item.  All items in the stack
should be subtypes of that one type.

func(string) vs func(substring) is a valid and useful
distinction.  A stack containing items of different
unrelated types is not.

But if you ever do find a use for such a thing, you can
disambiguate it by adding a one line inline function
which doesn't even generate any code, but just tells
the compiler what to call.  All the versions of such a
function should be together.  That you don't want to
put them together is not a good complaint, because
you shouldn't be using a stack of unrelated types of
objects in the first place.  I understand your point that
doing it your way can lead to a situation where you
have to modify a class you wanted to be closed to
further modification.  But I don't think that would be
a problem in real code, because I don't think a good
programmer would ever implement such a class that
way, and if a bad programmer did, I don't think a good
programmer would use it at all.  But if you were forced
to use it, you could always find a way to make it work,
even if that meant inheriting it into a kluge class and
putting the disambigation in that.

But the point is that function overloading is useful, and
it doesn't make sense to make a big mess of bad code
to try to prove otherwise.  A simple example such as
func(string) vs func(substring) is plenty to show the point.
Or func(string1,string2) vs func(substring1,string2).  To
make a concrete example, say func is cat, meaning
concatenate and return the concatenation.  Your way
would have you define the following:
cat_string_string(s1, s2: STRING)
cat_substring_string(s1: SUBSTRING, s2: STRING)
cat_string_substring(s1: STRING, s2: SUBSTRING)
cat_substring_substring(s1: SUBSTRING, s2: SUBSTRING)
and then call each of those functions as needed.  If you
called them a lot, your code would be cluttered.  As a
contrived example because I don't  have time for a better
one, suppose you concatenated two concatenations:

cat_string_string(cat_substring_string(s1,s2),cat_string_string(s3,s4))

All those encoded argument types make that a very messy
expression, and if your code is full of such messy
expresssions, it's likely to give someone a headache.



Fri, 02 Nov 2001 03:00:00 GMT  
 function overloading

Quote:

> On Sun, 16 May 1999 23:34:53 -0400, Jeffrey L Straszheim


<snip stuff>

Quote:
> But if you ever do find a use for such a thing, you can
> disambiguate it by adding a one line inline function
> which doesn't even generate any code, but just tells
> the compiler what to call.  All the versions of such a
> function should be together.

Please show me how to declare a "one line inline function" in
Eiffel? If you can't provide exact syntax how can I take you
seriously? I challenged you to do this before, will you respond?

Quote:
>  That you don't want to
> put them together is not a good complaint, because
> you shouldn't be using a stack of unrelated types of
> objects in the first place.  I understand your point that
> doing it your way can lead to a situation where you
> have to modify a class you wanted to be closed to
> further modification.  But I don't think that would be
> a problem in real code, because I don't think a good
> programmer would ever implement such a class that
> way, and if a bad programmer did, I don't think a good
> programmer would use it at all.  But if you were forced
> to use it, you could always find a way to make it work,
> even if that meant inheriting it into a kluge class and
> putting the disambigation in that.

Look, it was merely an example that syntactic overloading
can lead to contradictions. And regarding a collection
that might hold two or more types of objects, in my current
project I have one. I have an IO_MULTIPLEXER that holds
objects for i/o dispatch. It also holds object that will be
notified on timeout. The only commonality between the two
types is they are both called back, but there are enough
differences, not to mention complications regarding the
nature of i/o objects, that I've not made them a common type.
Now, you may criticise my design until the cows come home,
but I find it quite intuitive that I 'put' IO_HANDLER's (the
far more common case) and 'put_timeout_responder' for the
others. Moreover, it is very likely that someone might want
an i/o manager of some variety that is both an IO_HANDER and
a TIMEOUT_RESPONDER, but he may want it to recieve timeouts
only in certain cases, and i/o dispatch only in others. I
can't predict when he might want either. So, the user of
my class has the obvious and simple ability to 'put' it
in when he wants i/o dispatch (there is more to it than that,
but I shall not digress) and to 'put_timeout_responder' when
needed.

<snip canonical string/substring example>

To start with, please read the way ELKS currently handles
sring concatenation: namely append and extend.
Regarding substrings, if forced to implement them, for
some reason, I would inherit them from STRING: after all,
a substring is a type of string. Making it all work would
require the classes be designed together, but I think that
will usually be the case for good string-substring interaction.

So we have:

class STRING

    ... stuff ...

  feature append (other: STRING) is
       -- append other to Current.

    .... more stuff ...

end

class SUBSTRING

  inherit STRING redefine append end

   ... even more stuff ....

  feature append (other: STRING) is
      -- append other to Current.

    ... you guessed it ... stuff ...

end

Seems rather nice to me.

Regarding syntactic overloading: look, it is obvious that it will,
and does, lead to ambiguity, and Eiffel, without type-casts and
the like, gives no simple way to avoid this. Meyer goes into some
detail on why he avoided it, but I can sum it up in two points:

1. Semantic overloading allows the same name to have different
   behavior depending on the target of the call. This can be a
   dynamic decision (if inheritence is involved) or static (if
   not). For many cases this is all you need: e.g. 'put' is almost
   always how you add an object to a collection.
2. Syntactic overloading can lead to hard to resolve contradictions,
   especially when it depends on multiple arguments.

I really like the elegance of one name equals one feature. Perhaps
you could provide an example from a real Eiffel class you've desinged
where it would have been of sufficient benefit to justify changing
the current practice.

(Note: that it has proven useful in C++/Java is not an argument.)

--
--Jeffrey Straszheim
---Systems Engineer, Programmer
----stimuli AT shadow DOT net



Fri, 02 Nov 2001 03:00:00 GMT  
 function overloading

Quote:
> In any case, STACK_THAT_CAN_HOLD is horrible
> naming and factoring.  What goes in the stack should
> be of one class.  The different things it can hold should
> be subclasses of that one class.

Of course, it's easy to say this. And this is something I hear a lot on
cle.  But it's not really an appropriate solution. If you want a stack
class that'll hold either an Int_ref or a String, you're just SOL.
Saying "Just rewrite every class you need when you need another class
that can work with more than one" isn't very good software engineering.

From everything I've seen, Eiffel really is only effective at large
applications that are started from scratch, where the overhead of
rewriting many class libraries is dwarfed by the quantity of
application-specific code that needs to be written.

--
Darren New / Senior Software Architect / MessageMedia, Inc.
     San Diego, CA, USA (PST).  Cryptokeys on demand.



Fri, 02 Nov 2001 03:00:00 GMT  
 function overloading

Quote:

> On Mon, 17 May 1999 19:14:07 -0400, Jeffrey L Straszheim

> >Please show me how to declare a "one line inline function" in
> >Eiffel? If you can't provide exact syntax how can I take you
> >seriously? I challenged you to do this before, will you respond?
> It doesn't make sense to provide exact Eiffel syntax for
> syntactic overloading, because Eiffel doesn't have such
> a feature.  We were arguing about the value of syntactic
> overloading in general.  You seemed to be arguing that
> even in C++ there were serious problems with ambiguity,
> and I was explaining how such problems were easily
> resolved.  But the main point I was trying to make was
> not about C++ or Eiffel, but about the value of syntactic
> overloading in general.

Ah! I see our confusion. This whole time I thought we were
talking about Eiffel. My appologies.

Quote:
> The string/substring example was to make the point
> that syntactic overloading can be very useful.  You can't
> use the fact that another implementation is available to
> contradict that usefulness.  Usefulness does not imply
> being the only solution.  The syntactic overloading
> solution might be more elegant and lead to fewer bugs.
> You can also have different kinds of substrings, not just
> a class explicitly named SUBSTRING.  You can have a
> substring implied by iterators, for example.  How would
> you name a function to concatenate two substrings implied
> by string iterators?  With syntactic overloading, it's not a
> problem.  If you encode the types in the function name, it's
> a mess.

I really don't wish to belabor this point further, but I
will say this: if I used iterators as substrings, then
I'd treat them as iterators. Would an iterator of a subsection
of a list allow one to cat on the end of it? Then, as
a substring is an iterator, it would be done in exaclty
the same way, with the same feature name--which would
come from the class ITERATOR. Do you want to cat a string
on the end of your iterator? Try: iter.cat (str.iterator (1,string.length))
or some such. An iterator to the end of your string? Try:
str.cat (iter.to_string). This is not hard.

But you weren't talking about such overloading in Eiffel?
Very well. So could I possibly make the point that syntactic
overloading would not be useful in Eiffel? Furthermore, could
I suggest that, in the actual Eiffel libraries (e.g. ELKS,
Eiffel Base, Pylon, Gobo, etc.), the lack of such overloading
has not led to the sorts for "messes" that've you've alluded
to?

--
--Jeffrey Straszheim
---Systems Engineer, Programmer
----stimuli AT shadow DOT net



Fri, 02 Nov 2001 03:00:00 GMT  
 function overloading
On Mon, 17 May 1999 19:14:07 -0400, Jeffrey L Straszheim

Quote:

>Please show me how to declare a "one line inline function" in
>Eiffel? If you can't provide exact syntax how can I take you
>seriously? I challenged you to do this before, will you respond?

It doesn't make sense to provide exact Eiffel syntax for
syntactic overloading, because Eiffel doesn't have such
a feature.  We were arguing about the value of syntactic
overloading in general.  You seemed to be arguing that
even in C++ there were serious problems with ambiguity,
and I was explaining how such problems were easily
resolved.  But the main point I was trying to make was
not about C++ or Eiffel, but about the value of syntactic
overloading in general.

The string/substring example was to make the point
that syntactic overloading can be very useful.  You can't
use the fact that another implementation is available to
contradict that usefulness.  Usefulness does not imply
being the only solution.  The syntactic overloading
solution might be more elegant and lead to fewer bugs.
You can also have different kinds of substrings, not just
a class explicitly named SUBSTRING.  You can have a
substring implied by iterators, for example.  How would
you name a function to concatenate two substrings implied
by string iterators?  With syntactic overloading, it's not a
problem.  If you encode the types in the function name, it's
a mess.



Sat, 03 Nov 2001 03:00:00 GMT  
 function overloading
On Mon, 17 May 1999 22:50:55 -0400, Jeffrey L Straszheim

Quote:

>But you weren't talking about such overloading in Eiffel?
>Very well. So could I possibly make the point that syntactic
>overloading would not be useful in Eiffel? Furthermore, could

I was talking about syntactic overloading in general,
regardless of language.  But your argument that it
would not be useful in Eiffel is not convincing.  As
another example:

   string.append(
         "Lines: ", lines ,
         "  Words: ", words,
         "  Bytes: ", bytes
   )

That invokes append with six arguments, of which
three are literal strings and three are numbers.  How
would you do that without syntactic overloading?



Sat, 03 Nov 2001 03:00:00 GMT  
 function overloading

:
:But that's exactly the point. How does one get rid of the
:ambiguity? Please show the exact syntax. Sure the compiler
:will notice the problem. How does the programmer specify
:which routine should be used? I have a class that has a
:routine 'put' that responds differently for A's and for
:B's. If I have an object that is both and A and a B, what
:should I do?

Sather works by matching the declared types of dummy arguments (not
run-time types of actual objects) to the declared types (and numbers)
of variables.  There is no 'overloading' based on return type.

If a direct match isn't possible, you would put the thing to be passed
into a new variable whose type exactly matches the desired routine.

If it is ambiguous, the call is declared to be erroneous and will
not compile.

In practice, the overloading is used most frequently over types of
terminal concrete classes, and then there is ambiguity.  An argument
matches or it doesn't.  The static overloading results in fast
executables and natural expressivity.

The workaround I describe is needed very infrequently.

I agree that the rules ought to be straightforward, and which
routine is called must be strictly determined at compile time.

I find Sather's solution to be useful and efficient, in a language
intentionally similar to Eiffel.

--
*        Matthew B. Kennel/Institute for Nonlinear Science, UCSD          
*
*          "do || !do;  try: Command not found"
*                                         /sbin/yoda --help

*                                         /sbin/kosh --help



Sun, 04 Nov 2001 03:00:00 GMT  
 
 [ 25 post ]  Go to page: [1] [2]

 Relevant Pages 

1. C4:Function Overloading

2. Function Overloading

3. Function overloading in MASM

4. Function overloading in MASM

5. gnat and function overloading

6. Function overloading

7. Function overloading/ambiguity

8. Function overloading

9. standard question: function overload

10. Function Overloading Without Typechecking

11. FORTRAN, C, C++ and function overloading

12. function overloading

 

 
Powered by phpBB® Forum Software