[Aldor-l] exports and constants

Ralf Hemmecke ralf at hemmecke.de
Fri Jul 21 04:05:36 EDT 2006


Hi again,

>> ---BEGIN aaa.as
>> #include "aldor"
>> import from String, TextWriter, Character;
>>
>> define CatA: Category == with { }
>> define CatB: Category == with { }
>> define SomeCat: Category == with { CatA; CatB; }
>> Dom: SomeCat == Integer add;
>>
>> A == Dom;
>> B: CatA == Dom;
>> H: CatA == Dom add;
>>
>> stdout << "A has CatA: " << ( A has CatA ) << newline;
>> stdout << "A has CatB: " << ( A has CatB ) << newline;
>> stdout << "B has CatA: " << ( B has CatA ) << newline;
>> stdout << "B has CatB: " << ( B has CatB ) << newline;
>> stdout << "H has CatA: " << ( H has CatA ) << newline;
>> stdout << "H has CatB: " << ( H has CatB ) << newline;
>> ---END aaa.as
>>
>> You get...
>>  >aldor -grun -laldor xxx.as
>> A has CatA: T
>> A has CatB: T
>> B has CatA: T
>> B has CatB: T
>> H has CatA: T
>> H has CatB: F
>>
>> In particular, that "B has CatB" is a bit surprising, isn't it?

> Maybe I completely lost my point now (probably), but isn't it good that 
> B has CatB?

Well, I would have no problems with that semantics, but in my 
experiments I had the impression that this is not always the case.
There is need to write up (as Martin suggests) one program that shows 
all the peculiarities. That should become a testcase for the compiler.
But in order to do this, it would be good to learn how the language (not 
the compiler) is supposed to behave.

> If B would not have CatB, things like
> 
> func( R: Ring, a: R, b: R ): R == {
>     if R has Field then
>     {
>         a / b;
>     } else {
>         a * b;
>     }
> }
> 
> would never allow to enter the true branch of the if statment.

See, that was the demonstration in the last part of my previous mail.
(See the line
   stdout << (if b then isA?()$MyPkg(A) else isA?()$MyPkg(B));
in that main function.)
If one passes a domain directly into a function (MyPkg in that case) 
then one would see the additional structure inside the MyPkg function.
If, however, you first say something like

X: CatX == if zero? #arguments then (A add) else (B add);

and pass X to MyPkg, then, of course in MyPkg you don't see more than a 
CatX structure. And that would be reasonable, since X is defined to be a 
new domain with declared exports CatX.

> Consider
>   func( Fraction Integer, 1, 1 )
> . It can be rewritten to
> 
> --creating new scope
> ...
> --fixing parameter values in new scope
> R: Ring == Fraction Integer;
> a: R == 1;
> b: R == 1;
> 
> --entering function body
> if R has Field then
> {
>     a / b;
> } else {
>     a * b;
> }
> 
> which connects it to our discussion. So I guess the fact "B having CatB" 
> is essential!

Nice. And I agree, but the point is if you say

X: Ring == Fraction Integer;
func(X, 1, 2);

or

X: Ring == Fraction Integer add;
funct(X, 1, 2);

probably makes a difference. In the first case I'd expect 1/2, in the 
second 2 as a result. Don't you agree?

> But why is "H has CatB" false?
> I (now) like that as well. So the add is kind of a "forget" operator.
> It allows you to chop off parts of a domain you do not need--or would 
> break the semantics.
> AdditivieButNotArithmeticInteger: AdditiveType == Integer add;
> 
> Then AdditivieButNotArithmeticInteger is not of type ArithmeticType.

Exactly. And that is perfectly fine, since it is exactly what you had 
written.
You explicitly declared a (new) domain AdditivieButNotArithmeticInteger 
to just export AdditiveType.

Without the "add" the exports would be that of Integer at the time the 
compiler sees Integer (?). I don't know what type

MyInt: AdditiveType == Integer;

would have if it is declared with just libaldor in scope and you later 
use it with libalgebra in scope. Remember that libalgebra "extend"s 
Integer with a few more signatures.

I am missing a clear definition of statements like for "MyInt" above.

>> Has someone found a description in the Aldor UG of whether this is
>> intended to be so or this should be considered a bug in the compiler?

> It's not a bug; it's a feature.

If it's a feature then
     it's a bug in the documentation
     or
     I am to blind to find it properly documented.

>>> What I wanted to point out is that from a
>>> user perspective,
>>>
>>>   identifier: type == value
>>>
>>> should always refer to the same language construct. So
>>>
>>>   i: Integer == 2;
>>>
>>> and
>>>
>>>   i: Integer == 3;
>>>
>>> should be the same language construct,
>>
>> Where do you see a difference?
> 
> I do not see a difference between 2 and 3. That is the point. I also do 
> not see a difference between "Domain" and "Domain add". Both are domains 
> (However different ones of course, just as 2 is not equal to 3).

Oh. Your point of view is interesting. "Domain" and "Domain add" are 
different domains. Hmmm, thinking about it, I must somehow agree, the 
"add" probably does something like "_copy_(Domain)" (funny syntax!), it 
creates a new domain. But there is a little difference. You remember 
"add" creates a type context.

http://www.aldor.org/docs/HTML/chap7.html#3

>>>   Ident: Category == Domain;
>>>
>>> and
>>>
>>>   Ident: Category == Domain add;
>>>
>>> . Of course, "Domain" and "Domain add" are different things. No doubt
>>> about that. However, this differenc should be the only difference.
>>
>> There is a difference in the semantic, but I cannot remember that I have
>> found a proper explanation of what "Ident: SomeType == Dom" actually
>> means (no "add" here).
> 
> So you mean the "Ident: SomeType == " part means two different things, 
> regarding whether "Domain" or "Domain add" follows?

That is what we are talking about. Otherwise you wouldn't have the behaviour

 >> B has CatB: T
 >> H has CatB: F

from the program aaa.as above. My question is whether

B has CatB: T

should be considered a bug in the compiler or a feature of the language.

>> ---BEGIN aaa2.as
>> #include "aldor"
>> import from String, TextWriter, Character;
>>
>> define CatA: Category == with;
>> define CatB: Category == with;
>> define CatX: Category == with;
>>
>> A: CatX with { CatA } == add;
>> B: CatX with { CatB } == add;
>>
>> X: CatX == if true then (A add) else (B add); -- (*)
>>
>> stdout << "X has CatA: " << ( X has CatA ) << newline;
>> stdout << "X has CatB: " << ( X has CatB ) << newline;
>> stdout << "X has CatX: " << ( X has CatX ) << newline;
>> ---END aaa2.as
>>
>> aldor -grun -laldor aaa2.as
>> X has CatA: F
>> X has CatB: F
>> X has CatX: T
>>
>> That is clear, but why does the compiler reject the program without the
>> "add" in line (*)?
> 
> I'd consider that a bug in comparison of exports. Replacing your (*) 
> line by
> 
>   X: CatX == if true then (A at CatX) else (B at CatX);
> 
> gives a working program with output
> 
>   X has CatA: T
>   X has CatB: F
>   X has CatX: T
> 
> . So the problem (wild guess) is that the compiler Has problems with 
> seeing that the if statement gives CatX in both branches of the if 
> statement. Mainly because the types of A and B aro not equal. However, 
> you can hint the compiler. My code is telling him "The if part gives 
> CatX and the else part gives CatX". Then the compiler can infer, that 
> the whole "if" statement gives CatX. And it is at least the type of X 
> (which is CatX). So it matches.

COOL! So without the "add" the compiler gives X the type of what it sees 
on the right of "==". Now you declare that through "@CatX" to be CatX.
But, hey, why then you get

    X has CatA: T

??? That looks like cheating. So "A at CatX" in fact means consider A to be 
of type CatX (which it is anyway) but don't forget the true type of A 
(which is Join(CatX, CatA)). So the whole "@CatX" stuff, ist just to 
help the compiler to figure out that the "if" construction above yields 
something that has at least type CatX.

I am really not sure whether I like that. For me constructions like

X: CatX == Dom;

and

X: CatX == Dom add;

should (nearly) behave in the same way. In particular X should be 
something of type CatX and nothing more.

I said "nearly", because one might like to define something like

Tree: TreeCat == MyUnion(Node, MyCross(Tree, Tree)) add;

and for that the "type context" stuff would be necessary.

> However, your (*) with the "add"s tells the compiler to build two new 
> domains. This is not giving hints to the compiler, but forcing it to do 
> extra work and forcing it to produce extra code. However, due to the 
> add, it (probably) tries to cut off all parts of A and B, it does not 
> need. The compiler knows (due to the type CatX of X) that the "if" 
> statement has to be of CatX. Therefore, both branches of the "if" 
> statement have to provide CatX. So A is cut down to CatX and so is B.

I agree. Have you tried

X: CatX == (if true then A else B) add;

? That does not compile. I probably have to add "@CatX" as you did above.

>> I am actually a bit amazed that your program runs and gives expected
>> results. But what about...
>>
>> ---BEGIN aaa3.as
>> #include "aldor"
>> import from String, TextWriter, Character, MachineInteger;
>>
>> define CatA: Category == with;
>> define CatB: Category == with;
>> define CatX: Category == with;
>>
>> A: Join(CatX, CatA) == add;
>> B: Join(CatX, CatB) == add;
>>
>> MyPkg(X: CatX): with {isA?: () -> Boolean} == add {
>>     isA?(): Boolean == X has CatA;
>> }
>> main(): () == {
>>     import from CommandLine, Array String;
>>     X: CatX == if zero? #arguments then (A add) else (B add);
>>     stdout << isA?()$MyPkg(X) << zero? #arguments << newline;
>> }
>> main();
>> ---END aaa3.as
>>
>>  >aldor -fx -laldor aaa3.as
>>  >aaa3
>> FT
>>  >aaa3 1
>> FF
>>
>> It is clear with the "add" in the definition of X that we will always
>> see a F in the first column of the output. Can someone find a "nice"
>> construction where X is defined by a similar "if" construction and the
>> first F would turn into T?
> 
> Of course. Again, be nice to the compiler. He is old. He is buggy. He is 
> a bit rusty on the edges. And he is locked in, in a jail of non-free 
> source code. But help him. Do not force him to do extra work. Tell him 
> what you know, if he noods to be told.
> 
> X: CatX == if zero? #arguments then (A at CatX) else (B at CatX);
> 
> does the trick for me:
> 
> LC_ALL=C /opt/aldor/bin/aldor -M no-abbrev -C args=-Wopts=-m32 -Fx 
> -lalgebra -laldor aaa3.as && ./aaa3 && ./aaa3 xx
> cc1: note: -fwritable-strings is deprecated; see documentation for details
> cc1: note: -fwritable-strings is deprecated; see documentation for details
> TT
> FF

You were lucky. Of course, I had tried the "@" stuff. But my code was a 
little different and I ran into segfaults. I guess there are lots of 
problems hidden here.

>> Of course it would be easy to write
>>
>> main(): () == {
>>     import from CommandLine, Array String;
>>     b: Boolean := zero? #arguments;
>>     stdout << (if b then isA?()$MyPkg(A) else isA?()$MyPkg(B));
>>     stdout << zero? #arguments << newline;
>> }
>>
>> and obtain TT and FF, but that is not a "nice" solution.
> 
> I hope we both deem my solution to be "nice" :)

Yes, if I am not forced to write an extra "@CatX". The compiler should 
do that.

I hope all these mails about "A: CatA == Dom" are not too long.

Ralf



More information about the Aldor-l mailing list