comp.lang.ada
 help / color / mirror / Atom feed
* Dynamic binding
@ 2012-04-13 20:11 Katarina Olsson
  2012-04-14  8:43 ` Georg Bauhaus
  0 siblings, 1 reply; 9+ messages in thread
From: Katarina Olsson @ 2012-04-13 20:11 UTC (permalink / raw)


Hello,
I have a question about dispatching in Ada. As we know, methods in
java are always called on their objects. Let say that we have a class
Parent with methods a() and b(), where a calls b like this:

class Parent{

public void a() {
System.out.println("parent a");
b();
}

public void b(){
System.out.println("parent b");
}
}

Consider now the class Child extends Parent. It has overridden the b()
method like this:

class Child extends Parent{

@Override
public void b(){
System.out.println("child b");
}

}

When creating a Child object and calling the a() method,

Child c = new Child();
c.a();

the output will be the following on stdout:

>>parent a
>>child b

I have now attempted to reproduce the corresponding case in Ada. If I
create a tagged record Object in package Parent, and then the
corresponding procedures (or functions):

procedure A (This : access all Object);
procedure B (This : access all Object);

and then in package Child, I create a new Parent.Object:

type Object is new Parent.Object with null record

...and override the B method:

overrides
procedure B (This : access all Object)

This should correspond to the previous java case, shouldn't it? In any
case it seems to me that calling the A procedure on the Child Object,
would render the output

>>parent a
>>parent b -- (instead of child b)

Do I need to try again or have I understood it correctly? And if I
have, how would I best reproduce the java behaviour?








^ permalink raw reply	[flat|nested] 9+ messages in thread

* Dynamic binding
@ 2012-04-13 20:13 Katarina Olsson
  2012-04-13 20:55 ` Dmitry A. Kazakov
  2012-04-15 12:04 ` AdaMagica
  0 siblings, 2 replies; 9+ messages in thread
From: Katarina Olsson @ 2012-04-13 20:13 UTC (permalink / raw)


Hello,
I have a question about dispatching in Ada. As we know, methods in
java are always called on their objects. Let say that we have a class
Parent with methods a() and b(), where a calls b like this:

class Parent{

public void a() {
System.out.println("parent a");
b();
}

public void b(){
System.out.println("parent b");
}
}

Consider now the class Child extends Parent. It has overridden the b()
method like this:

class Child extends Parent{

@Override
public void b(){
System.out.println("child b");
}

}

When creating a Child object and calling the a() method,

Child c = new Child();
c.a();

the output will be the following on stdout:

>>parent a
>>child b

I have now attempted to reproduce the corresponding case in Ada. If I
create a tagged record Object in package Parent, and then the
corresponding procedures (or functions):

procedure A (This : access all Object);
procedure B (This : access all Object);

and then in package Child, I create a new Parent.Object:

type Object is new Parent.Object with null record

...and override the B method:

overrides
procedure B (This : access all Object)

This should correspond to the previous java case, shouldn't it? In any
case it seems to me that calling the A procedure on the Child Object,
would render the output

>>parent a
>>parent b -- (instead of child b)

Do I need to try again or have I understood it correctly? And if I
have, how would I best reproduce the java behaviour?








^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Dynamic binding
  2012-04-13 20:13 Dynamic binding Katarina Olsson
@ 2012-04-13 20:55 ` Dmitry A. Kazakov
  2012-04-14  6:41   ` Niklas Holsti
  2012-04-14  7:39   ` Simon Wright
  2012-04-15 12:04 ` AdaMagica
  1 sibling, 2 replies; 9+ messages in thread
From: Dmitry A. Kazakov @ 2012-04-13 20:55 UTC (permalink / raw)


On Fri, 13 Apr 2012 13:13:17 -0700 (PDT), Katarina Olsson wrote:

> I have a question about dispatching in Ada. As we know, methods in
> java are always called on their objects. Let say that we have a class
> Parent with methods a() and b(), where a calls b like this:
> 
> class Parent{
> 
> public void a() {
> System.out.println("parent a");
> b();
> }
> 
> public void b(){
> System.out.println("parent b");
> }
> }
> 
> Consider now the class Child extends Parent. It has overridden the b()
> method like this:
> 
> class Child extends Parent{
> 
> @Override
> public void b(){
> System.out.println("child b");
> }
> 
> }
> 
> When creating a Child object and calling the a() method,
> 
> Child c = new Child();
> c.a();
> 
> the output will be the following on stdout:
> 
>>>parent a
>>>child b
> 
> I have now attempted to reproduce the corresponding case in Ada.

You cannot. Ada's OO is properly typed. Java's model is not. The behavior
of A evidently shall not depend on whether Parent is a part of Child or
not. I.e. it shall always print:

   parent a
   parent b

This is what you get in Ada. To summarize:

1. The operation A is defined on the type Parent. Period. Overriding
changes nothing here. You override B for *another* type: Child. That does
not influence any inherited operations. I.e. the operation A inherited from
Parent stay intact.

2. Dispatch happens just once. When the specific type is determined through
dispatch, then it is known. End of story.

> This should correspond to the previous java case, shouldn't it? In any
> case it seems to me that calling the A procedure on the Child Object,
> would render the output
> 
>>>parent a
>>>parent b -- (instead of child b)
> 
> Do I need to try again or have I understood it correctly? And if I
> have, how would I best reproduce the java behaviour?

Java's behavior is re-dispatch.

But from the design point of view there are three choices (two good and one
not so good).

1. A proper design. If A calls to B which depends on the specific type from
the class (dispatches), then A is likely same for all instances from that
class. In this case you just declare it so:

   type Parent is ...
   procedure A (X : in out Parent'Class); -- You need no pointers in Ada
   procedure B (X : in out Parent);
   ...
   procedure A (X : in out Parent'Class) is -- A does not dispatch!
   begin
       Put_Line ("A is always A");
       X.B; -- This dispatches
   end A;
   procedure B (X : in out Parent) is
   begin
       Put_Line ("Parent's B");
   end B;
   --------------   
   type Child is new Parent with ...;
   overriding procedure B (X : in out Child);
   procedure B (X : in out Child) is
   begin
       Put_Line ("Child's B");
   end B;

This will print for Parent'Class which is a Child object:

   A is always A
   Child's B

A is called class-wide in Ada. All calls from it will be dispatching.
Class-wide operations represent in Ada the concept of generic programming:
operations defined for a whole set of types (the class).

2. Another properly typed variant is when both A and B are methods
(primitive operations in Ada terms), and you override both A and B in
Child:

   type Parent is ...
   procedure A (X : in out Parent); -- Dispatches
   procedure B (X : in out Parent); -- Dispatches
   --------------   
   type Child is new Parent with ...;
   overriding procedure A (X : in out Child);
   overriding procedure B (X : in out Child);

3. Java's design (re-dispatch). You can have it in Ada, but because
re-dispatch is unsafe (potentially breaks the implementation of the parent
type), you must be explicit about it. So that the reader could see the
hazard:

   type Parent is ...
   procedure A (X : in out Parent); -- You need no pointers in Ada
   procedure B (X : in out Parent);
   ...
   procedure A (X : in out Parent) is -- This dispatches
   begin
       Put_Line ("Parent's A");
       Parent'Class (X).B; -- Now it dispatches again,
                                 -- caution: type conversion!
   end A;

This will print for a Child object:

   Parent's A
   Child's B

In this example X of the type Parent is converted to a class, which makes
the result to remember that it was of the type Child in its life before A
was called.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Dynamic binding
  2012-04-13 20:55 ` Dmitry A. Kazakov
@ 2012-04-14  6:41   ` Niklas Holsti
  2012-04-14  7:39   ` Simon Wright
  1 sibling, 0 replies; 9+ messages in thread
From: Niklas Holsti @ 2012-04-14  6:41 UTC (permalink / raw)


On 12-04-13 23:55 , Dmitry A. Kazakov wrote:
> On Fri, 13 Apr 2012 13:13:17 -0700 (PDT), Katarina Olsson wrote:
>
>> I have a question about dispatching in Ada. As we know, methods in
>> java are always called on their objects. Let say that we have a class
>> Parent with methods a() and b(), where a calls b like this:
>>
>> class Parent{
>>
>> public void a() {
>> System.out.println("parent a");
>> b();
>> }

As Dmitry explained, in Java the call b() (re)dispatches, while in Ada 
is does not; if you want redispatch in Ada, you must ask for it by using 
a class-wide type.

Dmitry explained well the Ada alternatives. However, not all Ada users 
agree with Dmitry's view that redispatching is unsafe. I often use 
redispatching to get the behaviour I want. Of course, the user of an 
operation must be aware of which operations use redispatching, so 
redispatching behaviour must be documented in the descriptions of the 
operations.

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
       .      @       .



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Dynamic binding
  2012-04-13 20:55 ` Dmitry A. Kazakov
  2012-04-14  6:41   ` Niklas Holsti
@ 2012-04-14  7:39   ` Simon Wright
  2012-04-14  8:58     ` Dmitry A. Kazakov
  1 sibling, 1 reply; 9+ messages in thread
From: Simon Wright @ 2012-04-14  7:39 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> A is called class-wide in Ada. All calls from it will be dispatching.
> Class-wide operations represent in Ada the concept of generic
> programming: operations defined for a whole set of types (the class).

Looking at the Wikipedia article on generic programming, we have to
distinguish between _generic programming_ and _genericity mechanisms_;
but only after we've distinguished between three or more meanings of
_generic programming_:

* Ada-style generics, C++ templates ...

* the C++ STL approach of Musser and Stepanov (followed in spirit by 
  Ada.Containers)

* 'datatype generic programming' (I found
  http://www.cs.ox.ac.uk/research/pdt/ap/dgp/ - but that paper
  recognises that there are yet other uses of _generic programming_)

Not sure where Dmitry's meaning goes. One of the third type, I think.

I can see that an alternative name such as _classwide programming_ isn't
going to fly for the wider public!



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Dynamic binding
  2012-04-13 20:11 Katarina Olsson
@ 2012-04-14  8:43 ` Georg Bauhaus
  2012-04-14 17:17   ` Simon Wright
  0 siblings, 1 reply; 9+ messages in thread
From: Georg Bauhaus @ 2012-04-14  8:43 UTC (permalink / raw)


On 13.04.12 22:11, Katarina Olsson wrote:

> the output will be the following on stdout:
>
>>> parent a
>>> child b
>
> I have now attempted to reproduce the corresponding case in Ada. If I
> create a tagged record Object in package Parent, and then the
> corresponding procedures (or functions):
>
> procedure A (This : access all Object);
> procedure B (This : access all Object);

Just to make sure:
1) "access all Object" is not a pointer to "Object or a type derived
from Object". Just to Object.

2)It is, however, a pointer to something that is already
passed by reference: O-O types in Ada are pass-by-reference types.

(The "all" part requests that the object of type "Object" could
have been allocated from the heap (using "new"), or be declared
on the stack (without new).)

> ... then in package Child, I create a new Parent.Object:
>
> type Object is new Parent.Object with null record
>
> ...and override the B method:
>
> overrides
> procedure B (This : access all Object)
>
> This should correspond to the previous java case, shouldn't it?

The procedures will logically correspond to the Java methods
if you turn the This parameters into "Ada style" O-O references,
i.e., do not introduce pointers to references.

There will be dispatching if requested. The request is expressed,
for objects X of type "T, or derived from T", by writing

   X : T'Class  -- declaring a class-wide

when declaring objects, and

   T'Class (X)  -- converting to class-wide

when passing objects so that dispatching take place, dispatching
based on X's actual tag. (T'Class denotes a class of types, not
a class of objects.)

package O_O is

    type Parent is tagged null record;

    procedure A (This: in Parent);
    procedure B (This: in Parent);

    type Child is new Parent with
        record
           N : Natural;
        end record;

    overriding procedure B (This: in Child);

end O_O;

with Ada.Text_IO;

package body O_O is

    use Ada.Text_IO;

    procedure A (This: in Parent) is
    begin
       Put_Line ("parent a");
       B (Parent'Class (This));
    end A;

    procedure B (This: in Parent) is
    begin
       Put_Line ("parent b");
    end B;

    overriding
    procedure B (This: in Child) is
    begin
       Put_Line ("child b");
    end B;

    X : Parent'Class :=
        Child'(Parent with N => 42);

begin
    A (X);
end O_O;

$ ./o_o
parent a
child b
$



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Dynamic binding
  2012-04-14  7:39   ` Simon Wright
@ 2012-04-14  8:58     ` Dmitry A. Kazakov
  0 siblings, 0 replies; 9+ messages in thread
From: Dmitry A. Kazakov @ 2012-04-14  8:58 UTC (permalink / raw)


On Sat, 14 Apr 2012 08:39:41 +0100, Simon Wright wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>> A is called class-wide in Ada. All calls from it will be dispatching.
>> Class-wide operations represent in Ada the concept of generic
>> programming: operations defined for a whole set of types (the class).
> 
> Looking at the Wikipedia article on generic programming, we have to
> distinguish between _generic programming_ and _genericity mechanisms_;
> but only after we've distinguished between three or more meanings of
> _generic programming_:
> 
> * Ada-style generics, C++ templates ...

= static polymorphism

> * the C++ STL approach of Musser and Stepanov (followed in spirit by 
>   Ada.Containers)

= static polymorphism
 
> * 'datatype generic programming' (I found
>   http://www.cs.ox.ac.uk/research/pdt/ap/dgp/ - but that paper
>   recognises that there are yet other uses of _generic programming_)

= parametric polymorphism, probably static

> Not sure where Dmitry's meaning goes. One of the third type, I think.

One possible way to look how programming is evolving in order to handle
bigger problems is this one. It starts with individual values or objects
(level 1). Then it continues to sets of values sharing some similarities
(factored out as operations). These sets are types (level 2). The next
logical step is to consider similar types (mathematicians would call them
categories). This is generic programming (level 3). You can have
similarities in values of types from the set (e.g. extension, various
products), you can have similarities in operations (e.g.
inheritance/instantiation). It is complicated and still not sorted out with
all issues like LSP etc. I cannot tell anything useful about the level 4...

As for language-technical solutions for the level 3:

1. you can constrain types from a set (dynamically parametric polymorphism:
Ada's discriminated, variant types).

2. you can clone types while adjusting them (statically parametric
polymorphism: Ada's generics, Ada 83 "type is X new Y").

3. you can have types in the set bound by interface+implementation
inheritance (dynamic polymorphism: Ada's tagged types).

4. you can have only interface(-implementation) inheritance using type
conversions (Ada does not have this).

5. you can have it in the form of sets of types with nominally same
operations (ad-hoc polymorphism: overloading in Ada).

Each new level requires new language entities: value->type->class, and
faces the problem whether these should be mapped onto the entities of the
lower level. I.e. should a type be a value/object? What is the type of
value type? Should operations have types? What is the type of a class? Is
an instance from the class an object etc.

> I can see that an alternative name such as _classwide programming_ isn't
> going to fly for the wider public!

Classwide programming would be ambiguous, because it well applies to Ada's
generics:

generic
   type Number is range <>;
function "+" (Left, Right : Number) return Number;

*is* classwide because it is defined on the class Number (all signed
integer types).

Semantically "type S is range <>" and "type S derived from T" are just sets
of types. Only construction of these sets are different.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Dynamic binding
  2012-04-14  8:43 ` Georg Bauhaus
@ 2012-04-14 17:17   ` Simon Wright
  0 siblings, 0 replies; 9+ messages in thread
From: Simon Wright @ 2012-04-14 17:17 UTC (permalink / raw)


Thanks for that; some thinking required (may have to be postponed until
after our upcoming house move!)

--S



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Dynamic binding
  2012-04-13 20:13 Dynamic binding Katarina Olsson
  2012-04-13 20:55 ` Dmitry A. Kazakov
@ 2012-04-15 12:04 ` AdaMagica
  1 sibling, 0 replies; 9+ messages in thread
From: AdaMagica @ 2012-04-15 12:04 UTC (permalink / raw)


A nice discussion about dispatching and redispatching can also be found at

http://en.wikibooks.org/wiki/Ada_Programming/Object_Orientation#Redispatching



^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2012-04-15 12:04 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-13 20:13 Dynamic binding Katarina Olsson
2012-04-13 20:55 ` Dmitry A. Kazakov
2012-04-14  6:41   ` Niklas Holsti
2012-04-14  7:39   ` Simon Wright
2012-04-14  8:58     ` Dmitry A. Kazakov
2012-04-15 12:04 ` AdaMagica
  -- strict thread matches above, loose matches on Subject: below --
2012-04-13 20:11 Katarina Olsson
2012-04-14  8:43 ` Georg Bauhaus
2012-04-14 17:17   ` Simon Wright

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox