Hmm. Some more explaining is necessary.

On Monday, 25 August 2014 12:04:16 UTC+2, Pierre wrote:
>
> Thanks again for the explanations. I realize that there were many things 
> about Julia/Nemo which I had misunderstood. Let me explain a little, so I 
> can (i) embarrass myself a little more, and (ii) perhaps give an indication 
> of common mistakes, for anyone who would write a tutorial about Julia/Nemo 
> :-)
>
> Mistake (1): taking it for OOP. 
>

Julia is OOP!

There are two ways to do OOP. The first is with classes and usually single 
dispatch and the other is with multi-methods. The latter is the Julia way 
and it is more flexible.

There is a dual notion for data structures as well, and Julia supports that 
too, giving even greater flexibility. The combination of the two is more 
powerful than standard OOP, which can be very restrictive in practice.
 

> When hearing about the way Julia worked, I jumped when I saw it wasn't OO, 
> and then naturally was looking for ways to emulate OOP with Julia (rather 
> than make the effort of a paradigm shift). And with multi-dispatch, i 
> thought OK, if I want to write code that applies to objects of type A, B 
> and C at once, just declare them A <: X, B <: X and C <: X and define f(x 
> :: X). However this gave me the wrong intuition " A <: X is the same as A 
> inherits from X". 
>

None of that makes sense.

f(x :: X) is the way you write a function prototype in Julia. It 
corresponds to the following prototype in C.

void f(X x);

X is just a type, like int or float or double or MyType, etc. In Julia, you 
just write the type on the right, after a double colon, instead of on the 
left like C.

A <: X does not mean A is an object of type X. It means A is a subtype of 
X, where both A and X are types (one or both may be abstract types).

The way to write "A is an object of type X" is A :: X.

The way to write "X is a subtype of Y" is X <: Y.

But remember that subtype here *may* mean X is in the typeclass Y.


> At this point, the fact that abstract types could be instantiated was seen 
> as a limitation compared to OOP. 
>

No. There is no similar concept in OOP, except for languages like scala 
which have traits/interfaces/typeclasses. It's an extension over and above 
what is found in standard OOP languages.

You can also write all your Julia programs without any <: symbols if you 
want. And in fact you can leave all types out too and let Julia figure them 
out.

Types and subtyping simply allows you to restrict what is allowed. 
Otherwise everything is allowed, just like Python.
 

> And somehow, it is. 
>

No it is not. You never need to use the <: notation in Julia if you don't 
want to. You can just stick to values (objects) and types (classes) if you 
want. Then you have the same thing as standard OOP. You can even restrict 
yourself to single dispatch if you want, in which case you have OOP 
exactly. But there's no reason to restrict yourself in this way, because 
Julia offers all the other goodies on top of that.
 

> Except at the same time, the type system does many new things. Apples and 
> oranges, really.
>
> Mistake (2): taking types for sets. 
>

They sort of are. Formally a type is just a set of values. Well, not in a 
mathematical sense. But in some intuitive sense.
 
Types of course satisfy some calculus just as sets do and the rules of the 
calculus are somewhat similar, but not quite the same. Technically 
dependent types correspond exactly to predicates in the predicate logic, 
via Type theory (an extension of the Curry-Howard isomorphism). But that's 
all a bit complicated, so we informally think of types as sets.

One big difference is there are plenty of non-computable functions between 
sets. But the functions between types are always computable. But again, 
it's not even vaguely necessary to understand this to get the concept of a 
type. It's intuitively just a name given to the collection of all values 
which an object of that type can have.

This little discussion about names reveals another mistake of mine: 
> thinking of types as sets. I thought ZZ <: QQ for example. 
>

Yeah, the <: notation doesn't mean contained in. It's not a mathematical 
operator. It means "subtype of". There are three things the notation can 
mean:

1) If A <: B where A and B are types, then it means that if a function can 
take an argument of type B, then an argument of type A will work just as 
well in its place. In some sense, the set of values of type A is a 
restriction of the set of values of type B. This is pretty close to a 
subset meaning though technically it has more to do with the representation 
in bits on the machine than anything mathematical.

2) If A <: B where A is a type and B is an abstract 
type/typeclass/interface/trait, it means that a function which requires a 
type in class B can take the type A. This is not a subset meaning. It means 
the type A belongs to the typeclass B.

3) If A <: B where A and B are both abstract 
types/typeclasses/interfaces/traits, it means that a function which 
requires a type in class B can take a type in class A. This is a 
essentially a subset meaning, but the sets here are sets of types, not sets 
of values as in (1).

There aren't many examples of (1) in Julia that I can think of. Trivial 
ones such as Int <: Int are the only ones that come to mind. I really can't 
think of any other examples.

In fact, I think it is a general principle in Julia that concrete types 
cannot subtype one another. This isn't the case in some other languages, 
but it is the case in Julia. So (1) above essentially never happens, except 
for T <: T for concrete types T.
 
This is maybe an oddity, but it's not a restriction. You can still cast 
between types to your heart's content.

That's not even consistent with the previous mistake. In Sage say, i'm 
> guessing QQ is of type Field or something, which inherits from a type Ring 
> or something -- but not the other way around! 
>

Yeah in Julia you'd have QQ <: Field <: Ring.

The first <: in that is of sort (2) above. The second <: is of sort (3).

So mistake (1) should have led me to believe QQ <: ZZ. Oh well. 
>

We have neither QQ <: ZZ nor ZZ <: QQ. Both are concrete types and may not 
subtype each other. This is not essential, and in fact is not the case in 
some other languages. But it is the case in Julia.
 

>
> Mistake (3): thinking about Sage too much. To my discharge, ZZ in Sage is 
> an object, 
>

Correct. But classes are essentially objects in Python because everything 
is an object, pretty much. This really muddies the water. Better to think 
of classes and objects as being separate concepts.

Also better to think of ZZ as a class in Sage and elements of ZZ as 
objects, even though actually ZZ happens to be an object too because Python.

Roughly speaking a Julia value has some similarity to a Python object and a 
Julia type has some similarity to a Python class. That's a very misleading 
identification, but there is some truth to it.

Sage is a different beast to Python. As I mentioned, ZZ is not meant to be 
either an object or a class. It is meant to be a mathematical domain. And 
mathematical domains are being *modeled* in Python using classes, (which 
just happen to be objects in Python for the LOL's). That's of course a 
bastardisation of all that is good and pure. But both identifications occur 
for somewhat valid reasons.

Classes are objects in Python so that you can do things to classes just as 
you would any object in the language. The official reason is so that you 
can rename and import classes. But I rather think there's more to it than 
that.

And mathematical domains in Sage are modeled as classes because that is the 
most convenient thing in Python to model them with. Unlike Aldor, Python 
doesn't have a native domain or category concept. So you have to pick 
something that works well enough.

It is worth noting that mathematical categories cannot in general be 
modeled accurately with computer science types. There's a fundamental 
mismatch between category theory and types. This has led some 
mathematicians to completely redo the foundations of mathematics in terms 
of homotopy classes instead of category theory. And this can be modeled 
accurately in terms of Martin-L\"{o}f Type theory. This new foundation for 
mathematics is called the Univalent Foundation for Mathematics, and was 
developed primarily by Vladimir Veovodsky based on the Type theory of Per 
Martin-L\"{o}f.

I would suggest that a good dependent type system is just as good as a 
Martin-L\"{o}f Type Theory any day. So for most practical purposes we can 
model mathematics reasonably well with dependent types. We can't quite push 
the carpet down at the edges. But we can get most of the wrinkles out.

Sage attempts to model a dependent type system using classes in Python. I 
won't start a huge digression into the manifold problems with this 
approach. But it involves a lot of work, for one thing.

like 1/2, not a type or anything.
>

It's better to think of it as a type or class if you want to think of it as 
anything computational. It happens to be an object too. But that is an 
accident forced on you by Smalltalk, err I mean Python.
 

> This has unconsciously contributed to my confusion greatly. Also the fact 
> that there is a coercion from ZZ to QQ, and somewhere I must have taken A 
> <: B to mean "there is a coercion from A to B".
>

Ah, no. Coercion is another thing entirely. That is primarily a 
mathematical concept. Though there is a related computer science concept 
called conversion and promotion which has nothing to do with the 
mathematical concept of coercion, but which is the nearest related concept.

Mathematical coercion is a myth. There is no consistent formal foundation 
for coercion whatsoever.

The mathematical concept of coercion is nothing more than a bunch of 
incompatible and inconsistent informal notions that mathematicians carry 
around in their collective heads to relate the informal, inconsistent and 
incompatible definitions the carry around in their heads.

Any formal and consistent axiomatisation of computer algebra will deviate 
arbitrarily far from what any given mathematician thinks is reasonable.

Anyway, best to think of A <: B as meaning A is a subtype of B, where in 
Julia at least B needs to be an abstract type, except in the trivial A <: A 
case.

In a sense, you do want to have coercions from types in class A to types in 
class B where A <: B, usually. But it is much more subtle than that, 
especially in Julia where types can be parametric. Even if A <: B you don't 
automatically have T{A} <: T{B} in Julia. This would be called a covariant 
type system, whereas Julia is invariant.

So even if you had ZZ <: QQ in Julia (which you don't), you wouldn't 
automatically have Poly{ZZ} <: Poly{QQ}. And even if you did, that would 
have nothing to do with conversions and promotions because the conversion 
and promotion system can have arbitrary types in Julia and is completely 
decoupled from the subtyping system.

Decoupling is good because it gives you more flexibility to do whatever you 
want to do. You give your own meaning to things, and you only define the 
promotions and conversions you want.
 
Bill.

>
> Pierre
>
>
>
>
>
>
>>

-- 
You received this message because you are subscribed to the Google Groups 
"sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sage-devel+unsubscr...@googlegroups.com.
To post to this group, send email to sage-devel@googlegroups.com.
Visit this group at http://groups.google.com/group/sage-devel.
For more options, visit https://groups.google.com/d/optout.

Reply via email to