comp.lang.ada
 help / color / mirror / Atom feed
From: "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de>
Subject: Re: Access types as parameters
Date: Sat, 15 Aug 2009 11:47:52 +0200
Date: 2009-08-15T11:47:49+02:00	[thread overview]
Message-ID: <c3wd5mpebbb7.srlcuddwxdfp.dlg@40tude.net> (raw)
In-Reply-To: 4a858af5$0$24774$4f793bc4@news.tdc.fi

On Fri, 14 Aug 2009 19:03:52 +0300, Niklas Holsti wrote:

> Or we don't agree on the formalism, which seems to be the case for you 
> and me.

Once people agreed on a formalism there would be no place for
discussions... (;-))
 
>>> If your argument is just that a program with redispatching is more 
>>> complex and thus more likely to contain programming errors, I partly 
>>> agree; redispatching makes the sequence of invoked operations more 
>>> dynamic and thus possibly harder to grasp and make correct. But this 
>>> argument applies as well to any kind of run-time dispatching, not just 
>>> to *re*-dispatching.
>> 
>> I disagree. Dispatching does not make it more complex assuming that all
>> implementations of the primitive operation are conform the interface. You
>> write the client program in terms of another type, of the type T'Class.
>> There is nothing automatically more complex in T'Class than in T. 
> 
> If you assume that all operation implementations "conform to the 
> interface" (including semantics) then redispatching is no more complex 
> than dispatching; the effect of the (re)dispatching call is assumed to 
> be the desired one, whatever the actual type of the controlling operand(s).

LSP stuff, huh. No. T already conforms to T'Class, so why do you
re-dispatch? The answer is that semantically it does not conform, but the
thing you are dispatching to does. That is the complexity. You rely on
different behavior of T'Class and T. But according to the interface,
T'Class and T are interchangeable. So have broken that convention.

>> When you call an operation of the type S on T, that
>> is a type error to me. You have circumvented the type system, by an
>> explicit type conversion of T to T'Class. Do not we agree that type
>> conversions should be avoided?
> 
> I agree that type conversions "should" be avoided, but good grief, 
> sometimes you need them to express something, as in this case,

That is the point. What does it express at the semantic level? Why should
it be expressed in this form?

> because 
> Ada specifically uses the conversion T->T'Class to invoke dynamic 
> (re)dispatching. And of course this conversion is safe and does not in 
> any way "circumvent" the type system.

That depends on definitions. Address to access conversion is also "safe" in
some sense. The types involved in a conversion are formally different,
which implies different semantics. Once you change the semantics, it is
automatically unsafe.

>> Why do you dispatch again, you already checked the tag.
> 
> Because this gives me the functionality I want, of course.

That is clear, but if you say that the functionality you wanted is
re-dispatch itself, that could not justify it. There must be something else
in it, which raises the question of design. You have implemented something
using re-dispatch. My position is that it is a bad way to implement
anything. You disagree... (:-))

>> The type is determined,
> 
> Of course not, only the point (within the class) of the implementation 
> of the currently executing, (possibly) inherited operation (the caller) 
> is determined. The actual type, as you well know, is any type in 
> T'Class, although it is written "T" in the operation profile.

No, the actual type is T, just because the operation declaration tells so.

If you are in the operation inherited by S from T and you don't want it to
be T there, then why do have you inherited and not overridden it in S?
Something must be wrong in it.

>> the reader expects the code to correspond that type,
>> you break this convention.
> 
> That depends on the "reader". My convention is different from yours, and 
> I think my convention corresponds more closely to the (full) Ada 
> language, while yours assumes a subset of Ada that follows your design 
> rules.

Are you saying that the reader must be constantly aware that the type of
the actual parameter could be not the type the procedure deals with?

>> My concern is the semantics of the code.
>> Semantically a primitive operation has separate bodies for each type in the
>> class.
> 
> Yes, but they are represented by a smaller (sparse) number of bodies in 
> the program text, with the "missing" bodies supplied by inheritance. And 
> that is why the actual type of the actual parameter object is some type 
> in T'Class, not always T (as you well know...)

False inheritance cannot serve an argument, see above. You broke it when
inherited where you should have overridden. Then are trying to mend things
in some third place...

>> This gets broken in your design. I.e. it is a third way of how
>> bodies are decomposed. I may agree that the language could offer more than
>> one body per class (class-wide) vs. one body per type (primitive). But so
>> far, a design should conform to the existing model.
> 
> I fail to understand that. You seem to be claiming that the Ada "model" 
> does not really include redispatching, which is nonsense to me.

No it refers to other models of polymorphic operations, like extensible
bodies or the thing I described below.

>> but for some reasons am
>> not satisfied with the outcome. Why? Strange...
> 
> Come on, you know very well that the outcome using redispatching is 
> quite different from the outcome without redispatching. So of course my 
> reason is that I want the former outcome :-)

Yes, this is the core question. You don't want the semantics of the type T
being in an operation of.

> The same outcome could, of course, be gained in another design that does 
> not use redispatching, but at the cost of a different architecture, 
> which (in my view) had significant disadvantages such as code duplication.
> 
> I suggest that you show how you would design the Divide-and-Conquer 
> example that I described in my reply to Randy earlier today, and then we 
> can compare the two designs.

   type Subproblem is abstract ...;
   procedure Conquer (X : in out Subproblem) is abstract;
   type List_Of_Subproblems is ...; -- Container type of Subproblem'Class

   type Problem is abstract ...;
   function Divide (X : Problem) return List_Of_Subproblems is abstract;

A better case for re-dispatch is an operation defined in terms of other
operations. For example x*n defined as x+...+x, n times. you want to have a
standard version of *, but in some cases to have an ability to implement it
specifically.

I am using a sort of this:

   procedure Add (X : in out Item; Y : Item);
   procedure Mul (X : in out Item'Class; N : Positive);
private
   function Has_Accelerated_Mul (X : Item) return Boolean;
   procedure Accelerated_Mul (X : in out Item; N : Positive);

   procedure Mul (X : in out Item'Class; N : Positive) is
   begin
      if Has_Accelerated_Mul (X) then
         Accelerated_Mult (X, N);
      else
         ... -- Do it slowly
      end if;
   end Mul;

I don't like it, because it exposes Mul as class-wide, while Add is
primitive. It would be nice if Ada has supported a kind of decomposition,
with a fall back to a class-wide operation.

My empirical condition for all dispatching operations is that type tag
resolution should move strictly towards the root, and never backwards. I.e.
if you have a tag for T'Class,, you can narrow the set of candidates
ultimately to the single type, but you never widen the set.

>>>> that re-dispatch requires referential semantics,
>>> I don't see why,
>> 
>> Because of the type tag. You need same representation for T and T'Class to
>> have T -> T'Class as a view conversion.
> 
> That does not imply reference *semantics*, only pass by reference.

Formal argument is a view of the actual one. No difference.

If Ada had classes of by-value types, then Integer'Class would have a
different representation, and Integer -> Integer'Class would be a full
scale conversion producing a new object. Consequently there would no way to
re-dispatch from Float converted to Integer (in case they were in the same
hierarchy of types).

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



  reply	other threads:[~2009-08-15  9:47 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-07-17  8:39 Access types as parameters Rick
2009-07-17 15:03 ` Adam Beneschan
2009-07-17 16:28   ` Hibou57 (Yannick Duchêne)
2009-07-17 23:25     ` rickduley
2009-07-18  1:03       ` Randy Brukardt
2009-07-19 22:57         ` rickduley
2009-07-20  0:10           ` John B. Matthews
2009-07-20  8:13           ` Dmitry A. Kazakov
2009-07-21  0:34           ` Randy Brukardt
2009-07-21 14:34           ` Adam Beneschan
2009-07-23  2:11             ` Stephen Leake
2009-08-11 23:41               ` Randy Brukardt
2009-08-12  2:22                 ` Stephen Leake
2009-08-13  1:06                   ` Randy Brukardt
2009-08-13  8:34                     ` Niklas Holsti
2009-08-13  9:15                       ` Dmitry A. Kazakov
2009-08-13 20:13                         ` Niklas Holsti
2009-08-13 21:07                           ` Dmitry A. Kazakov
2009-08-14  9:27                             ` Niklas Holsti
2009-08-14 10:36                               ` Dmitry A. Kazakov
2009-08-14 16:03                                 ` Niklas Holsti
2009-08-15  9:47                                   ` Dmitry A. Kazakov [this message]
2009-08-15 19:19                                     ` Niklas Holsti
2009-08-16  8:32                                       ` Dmitry A. Kazakov
2009-08-16  9:52                                         ` Niklas Holsti
2009-08-16 12:38                                           ` Dmitry A. Kazakov
2009-08-16 13:21                                             ` Niklas Holsti
2009-08-16 17:58                                               ` Dmitry A. Kazakov
2009-08-14  4:07                       ` Randy Brukardt
2009-08-14 10:22                         ` Niklas Holsti
2009-08-18 12:22                     ` Stephen Leake
replies disabled

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