Inheritance in Julia

2,202 views
Skip to first unread message

privatl...@gmail.com

unread,
Mar 23, 2014, 6:02:06 PM3/23/14
to juli...@googlegroups.com
I need to create a hirarchy of types, something like this:

abstract Animal

type
Dog <: Animal
    weight
:: Real
end

type
Retriever <: Dog
    name
::String
end



The first inheritance is possible, the second isn't. This really confused me and a friendly IRC user pointed me to this link:

https://groups.google.com/forum/#!msg/julia-dev/p9bV6rMSmvY/cExeSb-cMBYJ

Apparently it's impossible to create subtypes of non-abstract types. Instead it is recommended to use delegation.
But in this example delegation doesn't make sense. A Retriever does not own a dog. A Retriever is a dog.
If I understood the previous discussion about this topic correctly, there are two issues with inheritance:

  1. "Tacking on fields" of a supertype to a subtype is problematic.
  2. Multiple dispatch becomes difficult in inheritance hirarchies.
I don't see the problem of tacking on fields. After all, a retriever is just a special kind of dog. To me it makes sense that a retriever should expose all fields of a dog. This feels intuitive to me. Actually not exposing the fields of a dog on a retriever would be strange. And having to retype all the fields can't be a solution, either.

The second issue is hard to dispute. I'm new to Julia and don't know how the compiler works. If the core developers say that this is a problem, surely they must be right. But intuitively I don't see the problem. You could still determine the best match, right ? A function could only be called with parameters of the specified type or one of its subtypes. And if a better match exists, if there's a function with the same name and a more specific signature, the compiler can call this function. There's only a problem if two functions would compete for the best match. But that's possible in abstract hirarchies, too :

function A (p1:: Real, p2:: Int64) ...
function A (p1:: Int64, p2:: Real) ...

A
(1,1)

So why would inheritance complicate this ?

Why should abstract types be treated any differently than normal, concrete types ?

Is the ability to create subtypes on the Julia roadmap ?



Isaiah Norton

unread,
Mar 24, 2014, 1:42:37 PM3/24/14
to juli...@googlegroups.com
There has been discussion of various aspects of this on several issues on GitHub. The most relevant is probably:
You'll see links to several other issues on that page.

James Porter

unread,
Mar 24, 2014, 2:06:24 PM3/24/14
to juli...@googlegroups.com
To save you some slogging through that issue: subtyping concrete types is never going to happen in Julia because if it were allowed, the compiler would not be able to determine the size of, say, `x::Complex` (since `x` actually could turn out to be some subtype of `Complex` with a different size at runtime). This would prevent the complier from generating efficient code, destroying performance.

The design of Julia compromises on the full dynamism of other languages in exchange for being able to generate very, very fast code; this is one of the places where the compromise shows.

—James

Stefan Karpinski

unread,
Mar 24, 2014, 5:00:21 PM3/24/14
to Julia Dev
The notion of subtyping concrete types may have arisen due to the fact that in the real world the types of things that we talk about are generally abstract, while concrete types in everyday experience are all singletons. Both "retriever" and "dog" are actually very broad abstract types – you need to supply a whole lot more information about representation and behavior before you have an actual instance of a dog. By the time you get to a full specification of a dog, there is at most one instance of it – the actual dog you are talking about.

The only real world things I can think of that are non-singleton concrete types are species of atomic particles. There are a vast number of electrons in the universe and they are indistinguishable from each other: describing something as "an electron" is, to the best of scientific knowledge, a complete description of it. Classes of particles like "fermion" and "boson" are abstract types, of which there are many specific kinds. If I ask what type of particle something is and the response is "fermion," then I might follow up with "but what kind of fermion?", and so on, until I get to a specific kind of fermion, such as "electron". When I know something is an electron, there are no more questions to ask. "Fermion" is an incomplete specification of a particle so it makes sense to talk about subtypes of fermions, whereas "electron" is a complete specification of a particle and it doesn't make sense to talk about subtypes of electrons.

The world of computers is quite different from physical reality. We have quite intentionally arranged it so that one bit is indistinguishable from another and there are many classes of things which, like electrons, have identical representation and behavior – Ints, Float64s, Complex{Float64}s, etc. Just as it makes no sense to subtype electrons, it makes no sense to subtype Int (unless you want to get into slicing up the domain of Int, but that's a different matter entirely). If a value is an Int, that already completely determines how it is represented and how it behaves. Integer, on the other hand, is an an abstraction like "fermion" and it makes sense to talk about specific kinds of Integer – precisely because saying that something is an Integer does not completely specify its representation and behavior.

While there are a number of practical reasons to disallow subtyping of concrete types, I think they all stem from the basic fact that subtyping a concrete type is logically unsound. A type can only be instantiated if it is *completely* specified, and it only makes sense to subtype something if it is *incompletely* specified. Thus, a type should either be abstract or concrete but not both. What object-oriented languages that allow the same type to be both instantiated and subtyped are really doing is using the same name for two different things: a concrete type that can be instantiated and an abstract type that can be subtyped. Problems ensue since there's no way to express which you mean. You end up with attempts to resolve this confusion like the "final" keyword and recommendations against ever subtyping classes that weren't intended to be abstract. But wouldn't it be better not to conflate the two things in the first place?

On Sun, Mar 23, 2014 at 6:02 PM, <privatl...@gmail.com> wrote:

Tobi

unread,
Mar 24, 2014, 5:21:27 PM3/24/14
to juli...@googlegroups.com
When I discovered that the following is possible, my need for subtyping concrete types vanished:

abstract MyType

function foo(x::MyType)
  x
.mySuperField + x.mySuperDuperField
end

It means that you can use fields on abstract types and thereby implicitly define certain requirements on fields that a subtype must have.

privatl...@gmail.com

unread,
Mar 24, 2014, 5:31:29 PM3/24/14
to juli...@googlegroups.com
I'm really happy that this is a conscious design decision which has practical advantages.

But still, I feel like the ability to inherit the fields of supertypes would be of great practical use. The idea that subtyping concrete types would be unnatural seems rather far-fetched to me. All particles would have common properties like a position and a velocity. A fermion could add additional fields and an electron would be even more specific. In the github discussion abstract types with fields were mentioned. This seems like a great approach to solve the problem. Are they on the roadmap ?

The concept that Tobi just introduced is intriguing. But I think that these type requirements should belong to the abstract type. Doesn't this make the code very hard to read ? If I want to subtype an abstract type, I have to search all functions that operate on this abstract type to puzzle together some kind of implicit interface ?

If abstract types could have fields, this problem of looking for all necessary fields and the tedious work of retyping all fields for every subtype would be removed.





Am Sonntag, 23. März 2014 23:02:06 UTC+1 schrieb privatl...@gmail.com:

Jacob Quinn

unread,
Mar 24, 2014, 5:36:24 PM3/24/14
to juli...@googlegroups.com
If you have an actual use case you could share where this feature would be useful, it'd be great to share it on the issues list. If I remember correctly, the discussion there evolved to the point where no one could really find a good use case that didn't also have some drawbacks as well, making the feature possibly not that useful.
In my opinion, I think a solution to the "interface" or "protocol" problem is what would really push things to the next level in terms of tackling the expression problem. (Stefan has mentioned he has some ideas on this forthcoming....)

-Jacob

Stefan Karpinski

unread,
Mar 24, 2014, 5:49:37 PM3/24/14
to Julia Dev
Adding the ability to specify fields for abstract types is what #4935 is about, but the whole issue kind of stalled out when we realized the feature isn't really buying you very much and may conflict with other, more useful features we want to add. My personal realization of this was here. Also note that specifying fields for abstract types is not the same as allowing subtyping of concrete types – the crucial distinction being that you still can't instantiate an abstract type.


On Mon, Mar 24, 2014 at 5:31 PM, <privatl...@gmail.com> wrote:

privatl...@gmail.com

unread,
Mar 24, 2014, 5:59:20 PM3/24/14
to juli...@googlegroups.com, quinn....@gmail.com
I'm afraid I got no specific use case.
But given the fact that it's already possible to demand certain fields on subtypes I think abstract types with fields should be a natural improvement.

If this is possible:

abstract Particle

function printPosition(p :: Particle)
    println
(p.pos)
end

Then you already got interfaces, even thought they are implicit. Every type that subtypes Particle must implement the field pos. It just makes sense to add this field to the type Particle.
  1. If the field is added to Particle, you can see the requirement for a position immediately. Instead of searching in the function definitions.
  2. If the field is added to Particle, you don't have to retype it for every subtype. Saves a lot of redundant code
  3. The type of the field is unclear. If it's added to Particle, you can make sure that it's a  2D Vector

In the github discussion the consensus seems to be that interfaces are necessary and fields on abstract types are problematic. I'm afraid I don't see the problem of abstract types with fields, since basically you already got this feature. What's the difference between demanding a field on an abstract type by using it implicitly in a function and adding it directly to the type ?

privatl...@gmail.com

unread,
Mar 24, 2014, 6:03:35 PM3/24/14
to juli...@googlegroups.com
Right now I have to develop in C++ for the university. There are no interfaces in C++ either, just abstract classes and I think that this concept is much better. An abstract class can just define method stubs, like an interface. But it also allows member variables, and concrete method definitions.

Maybe the same would make sense for Julia ?

But then multiple inheritance from abstract types should be possible. Is that a problem ? I guess multiple dispatch would become difficult, but then again, the problem with multiple dispatch would be just the same, if there were "normal" interfaces.


Am Sonntag, 23. März 2014 23:02:06 UTC+1 schrieb privatl...@gmail.com:

Tobi

unread,
Mar 24, 2014, 6:04:25 PM3/24/14
to juli...@googlegroups.com
Am Montag, 24. März 2014 22:49:37 UTC+1 schrieb Stefan Karpinski:
Adding the ability to specify fields for abstract types is what #4935 is about, but the whole issue kind of stalled out when we realized the feature isn't really buying you very much and may conflict with other, more useful features we want to add. My personal realization of this was here. Also note that specifying fields for abstract types is not the same as allowing subtyping of concrete types – the crucial distinction being that you still can't instantiate an abstract type.

I am also not so confident that #4935 is that important. But it is true that currently our requirements on the type are rather implicitly defined (quite similar to C++ templates). Sometimes I wish we had some more formal way to say: An AbstractArray must have the size method. This goes a little in the "C++ concepts" corner, which is mostly about giving sane compiler error messages.

Tobi

unread,
Mar 24, 2014, 6:10:42 PM3/24/14
to juli...@googlegroups.com, quinn....@gmail.com
fields are only one part of the story. The interface is about the fields and all the methods that are defined for an abstract type. And typically only the methods are the public interface of abstract type. Hence abstract types with fields do not really solve the "what are the requirements for this type" issue.

Ralf Hemmecke

unread,
Mar 24, 2014, 6:44:53 PM3/24/14
to juli...@googlegroups.com
> Just as it makes no sense to subtype electrons, it makes no sense to
> subtype Int (unless you want to get into slicing up the domain of
> Int, but that's a different matter entirely).

Really?

> If a value is an Int, that already completely determines how it is
> represented and how it behaves.

Natural numbers are specified by the Peano axioms. I'm not
aware of the fact that from that follows any conclusion about the
representation of natural numbers. It does also not follow what
operations are allowed or provided by natural numbers defined by the
peano axiom. If one wants to have +, define it, etc. If you want to
represent natural numbers via

0, S0, SS0, SSS0, ...
or
0, 1, 10, 11, ...
or
0, {0}, {0,{0}}, {0,{0,{0}}}, ...

is just a choice one has.

> Integer, on the other hand, is an an abstraction like "fermion" and
> it makes sense to talk about specific kinds of Integer – precisely
> because saying that something is an Integer does not completely
> specify its representation and behavior.

Ah, OK. You basically have the same opinion and Int is a specific Julia
type? No, you have Int8 up to Int128 as far as I can see. In other
words, Julia has nothing to represent natural numbers. Maybe I'm wrong,
but let's for the moment think that Int is the type that can hold any
integer.

Wouldn't it make sense to subclass it and specify all even integers?
That's just as well a ring and every operation would be the same, except
perhaps that even?(x) always returns true and that coercion of an
integer into an even integer might fail.

I agree, that example is too mathematical and mathematics has nothing to
do with nature, since it is entirely built from axioms.

Nevertheless, mathematics often can guide into some nice solutions.
In mathematics we define universal algebras by a carrier set and
operations that work on that set. The usual way to refine things is to
add more operations, but not to change the underlying set. Moved to the
world of languages... one might want to add new functionality do some
type without changing its representation. Would that be subtyping?

I haven't read much about "abstract types with fields", but it somehow
reminds me of what Aldor already implements since years. Aldor basically
has this universal algebra (with heterogeneous carriers) view and thus
subtyping is not a problem. Just an example,

EvenInteger: IntegerType with {
coerce: Integer -> %
} == Integer add {
Rep ==> Integer;
coerce(x: Integer): % == if even? rep x then per x else error "blah";
even?(x) == true;
}

Of course one can also subtype EvenInteger.

How would I program the type of all prime numbers in Julia? As I
understand, I cannot subtype Int for that. Are you saying that I can at
most get a function prime? that tests whether an integer is prime or not?

Ralf

Tim Holy

unread,
Mar 24, 2014, 8:26:06 PM3/24/14
to juli...@googlegroups.com
On Monday, March 24, 2014 02:59:20 PM privatl...@gmail.com wrote:
> I'm afraid I got no specific use case.
> But given the fact that it's already possible to demand certain fields on
> subtypes I think abstract types with fields should be a natural improvement.

Keep in mind that Julia was designed long after C++, and had plenty of
opportunity to learn from its mistakes. Don't think that because a feature is
missing in Julia that's present in C++, that this must be some deficit. Having
come from a C++ background myself, I know I simply needed some time to get
used to a new way of programming :).

That said, a really compelling use-case or analysis might do a lot to change
people's minds. Julia devs are a remarkably flexible lot, when you can come up
with a clear, convincing argument. For example, if you could argue
(concretely, meaning you actually analyzed the situation) that a given feature
improved productivity so much that it would eliminate 1000 lines from base, I
suspect your proposal would attract a lot of interest.

--Tim

Jacob Quinn

unread,
Mar 24, 2014, 8:29:00 PM3/24/14
to juli...@googlegroups.com
And Tim should know, since he's successfully navigated https://github.com/JuliaLang/julia/pull/5387

-Jacob

privatl...@gmail.com

unread,
Mar 25, 2014, 3:39:07 AM3/25/14
to juli...@googlegroups.com
Abstract types with fields could remove a lot of redundant code

abstract Vehicle

function getInfo ( v :: Vehivle)
    println
(v.name)
end

type
Car <: Vehicle
    weight
:: Real
    speed
:: Real
    prize
:: Real
    name
:: String
end

type
Bike <: Vehicle
    weight
:: Real
    speed
:: Real
    prize
:: Real
    name
:: String
end

type
Boat <: Vehicle
    weight
:: Real
    speed
:: Real
    prize
:: Real
    name
:: String
end

In this example we could save 8 lines of code by moving the fields to Vehicle. The code would become much more readable and easier to understand. And the problem of those implicitly demanded fields would be solved. The field name is used in the function getInfo() but that's not apparent at first sight. It would be much better to make name a field of the abstract type.

Right now you have to search all functions that use this abstract type, or any supertype of it, to check that your type has all the required fields.


Am Sonntag, 23. März 2014 23:02:06 UTC+1 schrieb privatl...@gmail.com:

privatl...@gmail.com

unread,
Mar 25, 2014, 3:53:17 AM3/25/14
to juli...@googlegroups.com
Since subtyping seems like a huge disadvantage to me, I wonder if this is possible:

The problem at hand is the performance issue, the compiler can't inline a concrete type, if it doesn't know its definite size.
I just checked, functions in julia use call-by-reference. If I pass a type to a function and its fields are modified inside, the type will be changed outside the function. So I guess you're passing some kind of reference or pointer to memory to the function, right ? Couldn't you do this with a subtype of a concrete type, too ?

type Retriever
    weight
:: Real
    name
:: String
end

type
Tom <: Retriever
end

function feed ( r :: Retriever)
    r
.weight += 1
end

function sit ( t :: Tom )
    println
( "good dog")
end

In this example, you've got the type Retriever. Most of the time you will work with this type. But there's one special dog, he's called Tom. Tom is also a retriever, so it makes sense to subtype the retriever type instead of rewriting all of its fields and methods. But Tom is special, he's been trained to sit.

I know, this is no especially useful example. But a type hirarchy like this is very well possible. One general type you'll use most of the time. And one specific subtype.
What about performance ?

A retriever can be fed. This increases its weight. The compiler will somehow pass the fields of the retriever to the feed function, probably by some kind of reference. But this is possible with Tom, too . If Tom is fed, he got all the fields of a retriever. These fields have the same memory offset as in a retriever. Couldn't you inline the references just as well ? You don't have to pass the entire new subtype. The function wouldn't need the new fields anyway. Inside of the function only the fields of retriever would be available. The parameter would be nothing more than a retriever.

I'm convinced that some kind of subtyping is crucial to allow useful type hirarchies.




Am Sonntag, 23. März 2014 23:02:06 UTC+1 schrieb privatl...@gmail.com:

Keith

unread,
Mar 25, 2014, 5:42:21 AM3/25/14
to juli...@googlegroups.com
I would hate to see Julia become a language with lots of deep type hierarchies.   Walking laboriously back through a hierarchy of classes just to be able understand how to construct an object required to call an otherwise simple function is one of my least favorite things about Java, for example.

I also think a shift toward class hierarchies would move the language away from one of Julia's major target audiences -- working scientists and engineers who currently use Matlab, Python, and R.  

Tobi

unread,
Mar 25, 2014, 6:36:03 AM3/25/14
to juli...@googlegroups.com
This is not a concrete answer to this problem but what you describe here is a very common thing in Java and C# where it is also absolutely common (an recommended) to program against interfaces which also don't have any fields.

One thing that is often recommended in such situations is to use composition instead of inheritance. Group some fields together to be a concrete thing that any of the types will have and then you won't have to repeat all the members.

In isolation the code duplication you describe seems huge. But it is restricted to field members. Using the generic programming capabilities of Julia I actually observe a lot less redundant code than I would write in other languages. So I would recommend starting to solve some real world problem in Julia and look if the restriction you found are really that important in practice.

Tim Holy

unread,
Mar 25, 2014, 9:15:31 AM3/25/14
to juli...@googlegroups.com
On Tuesday, March 25, 2014 03:36:03 AM Tobi wrote:
> So I would recommend starting to solve some real world
> problem in Julia and look if the restriction you found are really that
> important in practice.

+1. There's been a long tradition of people wishing for these things, and then
once they get started with Julia in earnest, they tend not to think they're so
important.

On Tuesday, March 25, 2014 12:53:17 AM privatl...@gmail.com wrote:
> I'm convinced that some kind of subtyping is crucial to allow useful type
> hirarchies.

If making this point is what you care most about, perhaps you should find an
area of Julia that is most likely to see a real-world need for inheritance.
I'd recommend Gtk, where I know Jameson has been butting up against
inheritance issues already. If you spend a month working with Jameson,
submitting patches to Gtk to make it better, you're likely to have a clearer
idea of what you actually want to get out of this, and far more compelling
examples to present to others.

--Tim

Jameson Nash

unread,
Mar 25, 2014, 9:17:19 AM3/25/14
to juli...@googlegroups.com
> You don't have to pass the entire new subtype. The function wouldn't need the new fields anyway

It is a very useful feature of Julia that you never need to deal with
incomplete types. It is incorrect to state that the new function
doesn't need the new fields -- languages that allow this (e.g. Java /
C#) also generally require a lot of typecasting, which Julia neatly
avoids by not having this "feature."

Also, I can save almost all of those lines of code, without resorting
to field inheritance.

abstract Vehicle

function getInfo ( v :: Vehicle )
println(v.info.name)
end

type VehicleInfo
weight :: Real
speed :: Real
prize :: Real
name :: String
end

type Car <: Vehicle
info :: VehicleInfo
end

type Bike <: Vehicle
info :: VehicleInfo
end

type Boat <: Vehicle
info :: VehicleInfo
end

Tobi

unread,
Mar 25, 2014, 9:41:01 AM3/25/14
to juli...@googlegroups.com
Indeed, Gtk.jl is one of the cutting edge projects in this regards and it reveals one thing that has not been mentioned in this thread and what is much more needed than subtyping concrete types: multiple inheritance.
In Java/C# it is possible to inherit from multiple interfaces and this is currently not possible in Julia. But the need for it might be very specific to Gtk.jl where the underlying Gtk C code supports multiple inheritance of interfaces. I know that Jamson is working on a workaround but still this might be an area where Julia is currently most limiting.

Stefan Karpinski

unread,
Mar 25, 2014, 11:43:54 AM3/25/14
to Julia Dev
On Mon, Mar 24, 2014 at 6:44 PM, Ralf Hemmecke <hemm...@gmail.com> wrote:
> Just as it makes no sense to subtype electrons, it makes no sense to
> subtype Int (unless you want to get into slicing up the domain of
> Int, but that's a different matter entirely).

Really?

> If a value is an Int, that already completely determines how it is
> represented and how it behaves.

Natural numbers are specified by the Peano axioms. I'm not
aware of the fact that from that follows any conclusion about the
representation of natural numbers. It does also not follow what
operations are allowed or provided by natural numbers defined by the
peano axiom. If one wants to have +, define it, etc. If you want to
represent natural numbers via

0, S0, SS0, SSS0, ...
or
0, 1, 10, 11, ...
or
0, {0}, {0,{0}}, {0,{0,{0}}}, ...

is just a choice one has.

Int is a specific integer-like representation and set of arithmetic behaviors. On a 64-bit machine Int is Int64, which uses 64 bits to represent two's complement signed integers from -2^63 through 2^63-1 on which arithmetic is done modulo 2^64. On a 32-bit machine Int is Int32, which is similar but with half as many bits. These are the integer representations that modern CPUs provide native operations for and has little to do with Peano's axioms.

> Integer, on the other hand, is an an abstraction like "fermion" and
> it makes sense to talk about specific kinds of Integer – precisely
> because saying that something is an Integer does not completely
> specify its representation and behavior.

Ah, OK. You basically have the same opinion and Int is a specific Julia
type? No, you have Int8 up to Int128 as far as I can see. In other
words, Julia has nothing to represent natural numbers. Maybe I'm wrong,
but let's for the moment think that Int is the type that can hold any
integer.

That's not the case – Int is what I described above. The closest thing to that is BigInt, but you could definitely have many other Integer types that choose different representations. An obvious (and useful) alternative would be to store integers inline until they reach a certain size and only then use heap allocated memory, as compared to our current BigInts which always use the heap, regardless of what value they store.

Wouldn't it make sense to subclass it and specify all even integers?
That's just as well a ring and every operation would be the same, except
perhaps that even?(x) always returns true and that coercion of an
integer into an even integer might fail.

<nit>The even integers aren't a ring – there is no multiplicative identity.</nit>

How would I program the type of all prime numbers in Julia? As I
understand, I cannot subtype Int for that. Are you saying that I can at
most get a function prime? that tests whether an integer is prime or not?

There are languages that encourage you to do this kind of thing with the type system, but Julia is not one of them. The type system is powerful enough that you could squeeze this kind of thing into it if you tried hard enough, but it's not recommended. I'm not sure what's wrong with using a function to test if an integer is prime or not – that seems pretty reasonable to me. On the other hand, making a type out of every subset of the integers strikes me as not especially reasonable. To continue the electron / Int analogy (which I recognize is imperfect), subtyping the integers is a bit like subtyping electrons by all the possible quantum states – position, momentum, etc. This is certainly a classification system of sorts, but just like making every subset of integers its own type, it gives you to an uncountable and intractable set of subtypes. Once you've narrowed it down to "electron", it's natural to switch from classification to description. Similarly, in programming languages you have to choose where to draw the line between types and values – and some languages go as far as making any set of values you can express into a type. However, that strikes me as pushing things too far. It is natural for the compiler to reason about how values are represented and how operations should be implemented. It's not especially natural for the compiler to reason about whether the result of some arbitrary computation is prime or not.

Stefan Karpinski

unread,
Mar 25, 2014, 11:50:58 AM3/25/14
to Julia Dev
On Tue, Mar 25, 2014 at 9:41 AM, Tobi <tobias...@googlemail.com> wrote:
Indeed, Gtk.jl is one of the cutting edge projects in this regards and it reveals one thing that has not been mentioned in this thread and what is much more needed than subtyping concrete types: multiple inheritance.
In Java/C# it is possible to inherit from multiple interfaces and this is currently not possible in Julia. But the need for it might be very specific to Gtk.jl where the underlying Gtk C code supports multiple inheritance of interfaces. I know that Jamson is working on a workaround but still this might be an area where Julia is currently most limiting.

I don't think that Gtk is alone in needing multiple inheritance.

Stefan Karpinski

unread,
Mar 25, 2014, 11:49:06 AM3/25/14
to Julia Dev
On Mon, Mar 24, 2014 at 5:59 PM, <privatl...@gmail.com> wrote:
In the github discussion the consensus seems to be that interfaces are necessary and fields on abstract types are problematic. I'm afraid I don't see the problem of abstract types with fields, since basically you already got this feature. What's the difference between demanding a field on an abstract type by using it implicitly in a function and adding it directly to the type ?

The problem is that declaring fields on abstract types is that if field access is just syntax for a particular method call, then it is really just a special case of explicit interfaces. We don't want to add a feature that addresses the special case and then later add a different feature that addresses the general case – especially if they don't quite line up.

Ralf Hemmecke

unread,
Mar 25, 2014, 12:31:53 PM3/25/14
to juli...@googlegroups.com
> <nit>The even integers aren't a ring – there is no multiplicative
> identity.</nit>

http://mathworld.wolfram.com/Ring.html

OK, it was a bad example. You seemingly come from another school.

> How would I program the type of all prime numbers in Julia? As I
>> understand, I cannot subtype Int for that. Are you saying that I can at
>> most get a function prime? that tests whether an integer is prime or not?

> There are languages that encourage you to do this kind of thing with the
> type system, but Julia is not one of them.

OK.

But some people even want to compute with species, for example, multiply
them.

http://www.risc.jku.at/people/hemmecke/AldorCombinat/combinatsu24.html#x38-560008.11

Simpler things would be to form products of ideals or factor rings.
Hmm, sounds like Juilia is nothing for me.

Ralf

Jacob Quinn

unread,
Mar 25, 2014, 12:39:29 PM3/25/14
to juli...@googlegroups.com
Hey Ralf,

I'm actually a little fuzzy on what you're hoping to accomplish or what you've tried so far with Julia, but if you have some code to share or an outline of what you're trying to do, there's several of us who are willing to help you see what's currently possible in Julia. There are definite advantages in Julia over other languages, as seen by the steady growth in the language over the last few years, and while it may not have as full a feature-set as other languages, the advantages are still a strong reason to dive in and give it a try. I think I'm safe in saying those of us who have actually taken the time to get familiar with how Julia can currently express problems have been more than satisfied.

Cheers,

-Jacob

Tobi

unread,
Mar 25, 2014, 12:53:12 PM3/25/14
to juli...@googlegroups.com, quinn....@gmail.com
Well, Julia is not made for implementing computer algebra systems, so I see no problem that it has restrictions in that area.
Julia already has a very wide scope from numerical programming over web programming to graphical user interfaces.

Stefan Karpinski

unread,
Mar 25, 2014, 1:01:05 PM3/25/14
to Julia Dev
On Tue, Mar 25, 2014 at 12:31 PM, Ralf Hemmecke <hemm...@gmail.com> wrote:
> There are languages that encourage you to do this kind of thing with the
> type system, but Julia is not one of them.

OK.

But some people even want to compute with species, for example, multiply
them.

http://www.risc.jku.at/people/hemmecke/AldorCombinat/combinatsu24.html#x38-560008.11

Simpler things would be to form products of ideals or factor rings.
Hmm, sounds like Juilia is nothing for me.

I'm curious, since you keep bringing up Aldor and all the features it has that seem to be exactly what you want – why you aren't just using Aldor? Is there something that it's missing that you were hoping Julia could provide, or is it just a matter of curiousity?

Spencer Russell

unread,
Mar 25, 2014, 1:58:25 PM3/25/14
to juli...@googlegroups.com
It's also worth noting that parametric types are yet another way to solve lots of the use cases where you might at first think you want fields on abstract types. In that case rather than an abstract supertype you use a concrete parametric type. I think this is especially useful when you have some behavior that you know ahead of time you want to delegate to the different subtypes. This can even cover some of the uses for multiple inheritance, as you can mix and match different behavior handlers.

abstract AnimalVoice

type Animal{V <: AnimalVoice}
    weight::Real
    legs::Integer
    name::String
    voice::V
end

function speak(a::Animal)
    speak(a.voice)
end

type DogVoice <: AnimalVoice
end

function speak(v::DogVoice)
    println("Woof!")
end

type CatVoice <: AnimalVoice
end

function speak(v::CatVoice)
    println("Meow.")
end

type FoxVoice <: AnimalVoice
end

function speak(v::FoxVoice)
    println("???")
end

For convenience it's also useful sometime to provide typealiases for instantiation:

typealias Cat Animal{CatVoice}
typealias Dog Animal{DogVoice}
typealias Fox Animal{FoxVoice}

Stefan Karpinski

unread,
Mar 25, 2014, 2:02:32 PM3/25/14
to Julia Dev
Nice. That's a great example :-)

Ariel Keselman

unread,
Mar 26, 2014, 5:46:07 PM3/26/14
to juli...@googlegroups.com
Were automatic "conversion rules" considered? they would try to convert a type when no method is found. This would allow easily "subclassing" like in the example below, where I "subclass" a Dict and change the setindex! method. All other methods would continue working as for the original dict

# Mydict definition:

type Mydict{k, v}
d::Dict{k, v}
Mydict() = new(Dict())
end

Mydict() = Mydict{Any, Any}()

function setindex!{k, v}(md::Mydict{k, v}, key, val)
print("my dict is special!")
md.d[key] = val
end

convert{k, v}(::Type{Dict{k, v}}, md::Mydict{k, v}) = md.d

# Usage:


md = Mydict()
md[1]=2         # <--- prints 'mydict is special'

delete!(md, 1)  # <-- currently doesn't work. It needs automatic conversion

abc

privatl...@gmail.com

unread,
Mar 27, 2014, 9:49:46 AM3/27/14
to juli...@googlegroups.com
Apparently there's a general agreement that subtyping is not necessary. That it would even make the code less readable because it might introduce long type hirarchies.

I know that without any actual experience it's really hard to contradict. But it seems to me that this strong opinion is based on the use of Julia as a language for scientific computing.
Sure, the various types of numbers are a beautiful example of your type system.

Nevertheless, Julia could be a fantastic general purpose language. Personally I would love to see python being replaced with it.
And for that, I think subtyping is crucial.

Gtk.jl will probably be the counterexample. A real world project implemented in julia with a complex type system. I've taken a look at the code. The structure feels rather strained. Lots of macros, lots of delegation. No offense meant, but this code would be better with interfaces or multiple inheritance. Personally I would prefer multiple inheritance, since interfaces don't support fields. With only interfaces there would have to be lots of getters and setters. Not too comfortable.

And once you got multiple inheritance you are at a level of complication where I think that those implicit interfaces on abstract types will make the code extremely hard to read. Really, why not move those fields into the abstract type ? That would keep them all in one place. What if there are two abstract types with an abstract subtype each and all of these four abstract types have their own implicit interface ? Inherit from the two last abstract types and you have to check all functions that receive one of these types as parameter to fulfill that interface. All functions on four different abstract types.

Tobi

unread,
Mar 27, 2014, 9:54:07 AM3/27/14
to juli...@googlegroups.com
Just one really quick reply. My "multiple inheritance" we mean the ability to inherit from mutiple abstract types. This is how "normal" interfaces work in Java and C#.

privatl...@gmail.com

unread,
Mar 27, 2014, 10:15:14 AM3/27/14
to juli...@googlegroups.com
Yes, that's what I mean, too.

And normal interfaces in Java or C# would behave differently. They can't inherit from each other. And they only document methods, not fields

Tobi

unread,
Mar 27, 2014, 10:40:17 AM3/27/14
to juli...@googlegroups.com

Am Donnerstag, 27. März 2014 15:15:14 UTC+1 schrieb privatl...@gmail.com:
Yes, that's what I mean, too.

And normal interfaces in Java or C# would behave differently. They can't inherit from each other. And they only document methods, not field

Interfaces in Java and C# can inherit from each other using "extends". In C# interfaces can also contain properties which are kind of fields. But this is another story. 

Stefan Karpinski

unread,
Mar 27, 2014, 11:15:32 AM3/27/14
to Julia Dev
Interfaces and multiple inheritance – excellent ideas and we'll have to add something along those lines. Fields declarations for abstract types – maybe, but that case is unclear. Subtyping concrete types – definitely not.

Carlos Mundi

unread,
Mar 28, 2014, 10:54:47 PM3/28/14
to juli...@googlegroups.com

On Monday, March 24, 2014 2:00:21 PM UTC-7, Stefan Karpinski wrote:
The only real world things I can think of that are non-singleton concrete types are species of atomic particles. There are a vast number of electrons in the universe and they are indistinguishable from each other: describing something as "an electron" is, to the best of scientific knowledge, a complete description of it. Classes of particles like "fermion" and "boson" are abstract types, of which there are many specific kinds. If I ask what type of particle something is and the response is "fermion," then I might follow up with "but what kind of fermion?", and so on, until I get to a specific kind of fermion, such as "electron". When I know something is an electron, there are no more questions to ask. "Fermion" is an incomplete specification of a particle so it makes sense to talk about subtypes of fermions, whereas "electron" is a complete specification of a particle and it doesn't make sense to talk about subtypes of electrons.


Let me help you off the hook completely. Stating that something is, for example, an 'electron' -- or any other soup of quarks and gluons -- does not in fact get us to an instance. All we have done to that point is specify allowed attributes (e.g., charge, spin) and behaviors (i.e., interactions with fields mediated by other particles).  Those are descriptions of a class, not of an instance.  To really specify an individual instance, we need to declare the full state-vector of the particle.  (This by the way implicitly entails specifying the full Lagrangian or Hamiltonian, including the influence of all particles and fields making up the system, and one might reasonably question the notion of an "individual" whose identity depends on its environment. Discuss!) Actually it gets a bit worse, because if the particle is a boson instead of a fermion, then state does not disambiguate individuals and we can only talk about an individual as one dimension of an indistinguishable-under-exchange subspace of an individuated many-body state. Despite appearances, I'm not arguing with you. I'm pointing out that even these real-world things (as close to real as quantum mechanics gets anyway) do not provide an example for which a real thing is not a singleton.  I can't think of anything I would call real which is not a singleton, though this may say more about my brain-dead epistomology than about rigorous ontology.  Time for another pint.

Net result: Once again we see that Julia is a really well thought-out design. I call this a feature of logical consistency, not a compromise relative to other languages.

Reply all
Reply to author
Forward
0 new messages