[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Axiom-developer] Cast = pretend in Spad/Aldor? (was: B#)

From: Ralf Hemmecke
Subject: Re: [Axiom-developer] Cast = pretend in Spad/Aldor? (was: B#)
Date: Wed, 23 Nov 2005 11:55:34 +0100
User-agent: Thunderbird 1.4 (X11/20050908)

Bill Page wrote:
On November 22, 2005 3:38 PM Peter Broadbery wrote:

Bill Page wrote:
Yet the ability to use 'pretend' is critical to the concept
of representation in the construction of Axiom domains.

For a perhaps overly abstract discussion of this see:

Just one comment to this website. I don't think that
rep: % -> Rep
could be seen as a forgetful functor. Surely, it forgets the signatures of % (ie, its category), but it also introduces a structure.

Take, for example,

IntegerGroup: Group == add {
  Rep == Integer;
  (x: %) + (y: %): % == per(rep x + rep y);

Here rep forgets the Group structure of % and gains (at least) the Ring structure of Integer.

So my question is: Does this feature of the Spad and Aldor
languages actually make them "weakly typed"?

I'd say it does, at least for some definitions of the term.
I'd very quickly follow up by saying 'but who cares', since
it's obvious that they occasionally have their uses (as Tim
suggests, system level code, and where you just know that
your domain is implemented in a particular way).  I've rarely
seen a need for the second use, but one persons app level
could be system level to someone else, I guess.

I would be interested to learn of any examples where this sort
of use of 'pretend' was essential, i.e. where it can not be
replaced with some operations defined on the underlying domains.

I think it was nowhere essential. If a programmer thinks for some efficiency reasons to pretend that some A is some particular type B that might come from the fact that A does not provide certain functions. I would argue, that in this case A is simply not rich enough. So the design was not the best from the beginning.

See also

I cannot remember that I have seen pretend being used in some essential way. Anyway, if it were essential, then I'd rather like to have all such domains defined at a very low level and forbid "pretend" for all users who are going to implement mathematics.

There is some use of "pretend" though, where I could not do without it.
bar(F: Field): F == ...
foo(R: Ring): () == {
  if R has Field then result:= bar(R);
                 else result:= 1;

The Aldor compiler should be able to compile such code, but the current implementation does not realize in all cases that in bar(R) the R is actually a field, so I'd have to say "bar(R pretend Field)". However, that is a weakness of the compiler and not a necessity for "pretend". (P.S.: I don't claim that this particular piece of code above does not compile, but I remember that I experienced cases, where the structure was similar.)

For Rep, rep and per, I (personally) believe they should have
been language primitives, except that add-inheritance confuses
the issue a little. They should definitely be thought of as

I fully agree, although I don't quite understand that part "except that add-inheritance confuses the issue a little". But I think the language designers were minimalistic. Instead of introducing two primitives "rep" and "per", they introduced only "pretend".

There is an idea of adding a third operation 'per?', defined
by the programmer which tests if an object of type Rep is
really a member of %, and would be called immediately before
each 'per' operation.  I'd hate to be forced to write it each
time though.

How can they be different anyway? To me it is even not completely clear whether Rep is a language primitive or not. I don't remember that I have read anything about Rep being a primitive, furthermore, some time ago one would have written "Rep ==> Integer" and not "Rep==Integer" as it is suggested now. See (subsection Representation).

since the representation is supposed to be purely internal to
the domain, right?.

And this is an advantage. Let's look at the Aldor libraries. There are two variants, and The second one is a "DEBUG" version and sometimes quite handy to find bugs. Take, for example, the implementation of PritiveArray in both libraries.

It starts like this.

PrimitiveArray(T:Type): PrimitiveArrayType T == add {
  import from Machine;
  Rep == Record(sz:Z, data:Arr);
  local size(x:%):Z == {import from Rep;
    empty? x => 0; rep(x).sz
  local arr(x:Arr, n:Z):% == {import from Rep;
    zero? n => empty; per [n,x]
  local data(x:%):Arr == {
    import from Rep;
    empty? x => (nil$Pointer) pretend Arr;
  Rep == Arr;
  local data(x:%):Arr     == rep x;
  local arr(x:Arr, n:Z):% == per x;
  local arr(x:Arr):%      == per x;
  array(p:Pointer, n:Z):% == arr(p pretend Arr, n);
  pointer(a:%):Pointer == data(a) pretend Pointer;

So if you are going to use PrimitiveArray later in your program, you could hardly use "pretend" until you happen to have the sources and know the dependency on the DEBUG flag.

But for the outside world both are indistinguishable, because they are both of PrimitiveArrayType(T).

Oh, I am just realizing here is also a "pretend Arr". That is low level programming and completely hidden in PrimitiveArray. But this also looks like efficiency considerations. If there were a better documentation of Arr available then it would certainly be unecessary. But then maybe Arr would use "pretend" or is completely implemented in C or so. One has to start somewhere, so consider PrimitiveArray as a primitive type and never worry about "pretend" anymore when building on it.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]