Traits in lieu of abstract types?

784 views
Skip to first unread message

John Myles White

unread,
Jun 26, 2015, 2:36:08 PM6/26/15
to juli...@googlegroups.com
After Mauro Werder's talk at JuliaCon today, Oscar Blumberg proposed an idea that I really like: replace abstract types with traits in a future version of Julia. For example, the type Number would become a trait.

We have discussed this idea before, but I'd like to consider it again. What are the main arguments against it?

-- John

Stefan Karpinski

unread,
Jun 26, 2015, 3:28:19 PM6/26/15
to juli...@googlegroups.com
Traits are really appealing, but I feel that they need more language support before they're really nice to use. Once we've got that figured that out, they could very well become the way type hierarchy is implemented, so that we only have a single mechanism with some syntax.

Jacob Quinn

unread,
Jun 26, 2015, 3:31:31 PM6/26/15
to juli...@googlegroups.com
Agreed. For a feature that would be so proliferated, it should have more "first-class"-ness than a macro.

John Myles White

unread,
Jun 26, 2015, 3:44:08 PM6/26/15
to juli...@googlegroups.com
Definitely. I'd love to see 0.6 be the traits update.

 -- John

Scott Jones

unread,
Jun 26, 2015, 4:22:07 PM6/26/15
to juli...@googlegroups.com
Yes - and Jacob at lunch had some arguments about wanting to maybe use it *with* types, maybe he could elaborate on that.
How does the idea of using just traits fit with Jeff's subtyping?
All this stuff today is just a cornucopia of things I want (now!)

Mauro

unread,
Jun 26, 2015, 4:27:53 PM6/26/15
to juli...@googlegroups.com
So, who's going to clean up after the traitocalypse?

Anyway, my immediate plan is to put together a PR for Julia based on
SimpleTraits.jl. This will provide macro sugar for Holy traits, which
would formalize their usage in Base a bit.

To get full support for traits alike to Traits.jl into Base will require
a lot of thought & work. To actually replace subtyping with traits
would be a huge amount of work...

Whilst at JuliaCon, I'd be interested to talk about signature
matching/dispatch in Julia and how that is similar to what Traits.jl
uses for traitdef and traitfn.

On Fri, 2015-06-26 at 15:44, John Myles White <johnmyl...@gmail.com> wrote:
> Definitely. I'd love to see 0.6 be the traits update.
>
> -- John
>
> On Jun 26, 2015, at 3:31 PM, Jacob Quinn <quinn....@gmail.com> wrote:
>>
>> Agreed. For a feature that would be so proliferated, it should have more "first-class"-ness than a macro.
>>
>> On Fri, Jun 26, 2015 at 3:27 PM, Stefan Karpinski <ste...@karpinski.org <mailto:ste...@karpinski.org>> wrote:
>> Traits are really appealing, but I feel that they need more language support before they're really nice to use. Once we've got that figured that out, they could very well become the way type hierarchy is implemented, so that we only have a single mechanism with some syntax.
>>

Scott Jones

unread,
Jun 26, 2015, 4:58:23 PM6/26/15
to juli...@googlegroups.com


On Friday, June 26, 2015 at 4:27:53 PM UTC-4, Mauro wrote:
So, who's going to clean up after the traitocalypse?

You need to pick a new name, -"ocalypse" was already used! ;-)
(and I want dibs on "-narok" for "Stringnarok" :-) )

Anyway, my immediate plan is to put together a PR for Julia based on
SimpleTraits.jl.  This will provide macro sugar for Holy traits, which
would formalize their usage in Base a bit.

To get full support for traits alike to Traits.jl into Base will require
a lot of thought & work.  To actually replace subtyping with traits
would be a huge amount of work...

Does there really need to be "one true way" for everything?
I like the typing in Julia, I liked what Jeff showed for subtyping today, and I also like traits.
I've been seeing this same argument with chaining going on.
 
Whilst at JuliaCon, I'd be interested to talk about signature
matching/dispatch in Julia and how that is similar to what Traits.jl
uses for traitdef and traitfn.

+1 for Tim's trick, and your implementation. 

Stefan Karpinski

unread,
Jun 26, 2015, 5:33:25 PM6/26/15
to juli...@googlegroups.com
I suspect switching from single inheritance to traits can be done in a backwards compatible way, so there may be no traitpocalyse at all.

Changes to strings might be more disruptive, but only if you were digging around in the internals of strings, which I suspect relatively little code does – although fixing that code could be fairly tricky.

Rory Finnegan

unread,
Jun 26, 2015, 10:30:31 PM6/26/15
to juli...@googlegroups.com
I would also be interested in seeing traits in julia soon. Unfortunately, I'd be a -1 for Tim's trick and the current implementation of Traits.jl, since they just seem like a hack and are kind of confusing to use. Mauro, I'd also be interested in talking about this while at JuliaCon.

Mauro

unread,
Jun 27, 2015, 6:47:39 AM6/27/15
to juli...@googlegroups.com
> Unfortunately, I'd be a -1 for Tim's trick and the current
> implementation of Traits.jl, since they just seem like a hack and are
> kind of confusing to use. Mauro, I'd also be interested in talking
> about this while at JuliaCon.

Sounds good, I'll be interested to hear about the confusion. I'll be at
the workshops today (probably at JuliaOpt's, Arch's and Viral's).

Jeffrey Sarnoff

unread,
Jun 30, 2015, 8:34:21 PM6/30/15
to juli...@googlegroups.com
I see traits and abstract types as re-enforcing rather than substituting. Traits are an elegant way to ungather aor reweave constitutive gestalts -- to simplify/disentangle/clarify. Abstract types are projective organizers and subsumptive expressors.  Traits are as effectiveness amplifiers. Abstract types are as intent harmonizers.  Julia's facility with making technical communication easier is supported with each.

Mauro

unread,
Jun 30, 2015, 9:06:10 PM6/30/15
to juli...@googlegroups.com
That is a nice philosophical way to look at it! I think one area where
they clash is: should I make this a type-dispatch function or a
trait-dispatch function? How to pick between the two?

On Tue, 2015-06-30 at 20:34, Jeffrey Sarnoff <jeffrey...@gmail.com> wrote:
> I see traits and abstract types as re-enforcing rather than substituting.
> Traits are an elegant way to ungather aor reweave constitutive gestalts --
> to simplify/disentangle/clarify. Abstract types are projective organizers
> and subsumptive expressors. Traits are as effectiveness amplifiers.
> Abstract types are as intent harmonizers. Julia's facility with making
> technical communication easier is supported with each.
>
>
> On Friday, June 26, 2015 at 3:44:08 PM UTC-4, John Myles White wrote:
>>
>> Definitely. I'd love to see 0.6 be the traits update.
>>
>> -- John
>>
>> On Jun 26, 2015, at 3:31 PM, Jacob Quinn <quinn....@gmail.com

Pulkit Bhuwalka

unread,
Jul 1, 2015, 12:09:26 AM7/1/15
to juli...@googlegroups.com

In terms of deciding whether something should be a "type-dispatch" function or a "trait-dispatch" function, I feel that in general all code that is exposed out of a module/library should be "trait-dispatched".

For eg., if someone writes a Julia package, that's expected to be extended. eg., a sparse matrix interface (with multiple implementations), a DataFrame interface (with multiple implementations under the hood). Traits here cleanly ensure that someone implementing their own extension/package need only to adhere to the trait interface. It removes the baggage of using existing types from an implementation (though of course they can subtype and use it if they want to).

The way I think of it, traits are a way to define a contract between code, and abstract away implementation. Abstract types allow sharing of code and functionality, and provide a common interface. But the combination of the two together is inherently messy. Within a module code can always be shared/reused using Abstract types. Coming from a more object-oriented background, traits aka interfaces allow to move code from an "is-a" relationship to a "has-a" relationship which ends up being cleaner.

I might be off base here since I have much lesser context on the motivations behind this, and the internal implementation of Julia. So pardon me if this is a little irrelevant - just trying to help :-)

Best

--
Pulkit

Jeffrey Sarnoff

unread,
Jul 1, 2015, 10:09:19 PM7/1/15
to juli...@googlegroups.com
Different sorts of trait, all good ...

Say we, in the abstract, specialize a more general abstraction of interfacing. When realizing this more specific interfacing familiy, we may implement several realizations -- each doing the same things (the interface) using different, context-driven ways. With those implementations, gimme traits,  Dispach doesn't hiccup (both abstract types and traits likely share code that makes-it-work) . When we find we specified those traits so artfully that they are more generally useful, people use them working in other abstract type paths.  There, it is reasonable and transparently coherent  to guide dispach with type and by trait.

Rory Finnegan

unread,
Jul 7, 2015, 4:23:42 PM7/7/15
to juli...@googlegroups.com
I'll just mention Interfaces.jl as an alternative to Traits and Tim's trick here if folks want to take a look. I think it is more intuitive to use, but I'm biased.

Scott Jones

unread,
Jul 7, 2015, 5:07:13 PM7/7/15
to juli...@googlegroups.com
That looks nice to me also, but, is there any reason why you couldn't use both?
(maybe I'm the exception, but I just don't see things as this *or* that, I think Julia can support a lot of different good programming styles).

Tobi

unread,
Jul 7, 2015, 5:54:16 PM7/7/15
to juli...@googlegroups.com
Hi Rory, this looks very interesting. Have you seen the julia issue about interfaces: 


One idea I implemented in https://github.com/JuliaLang/julia/pull/7025 is to hook the interface validation into the showerror method which gives nice error messages when a new type does not fully implement an interface. The prototype had some limitations though.

Cheers,

Tobi

Mauro

unread,
Jul 8, 2015, 8:03:45 AM7/8/15
to juli...@googlegroups.com
Hi Rory,

good to see that you're looking into this too!

If I understand correctly, your implementation is semantically
equivalent to single-parameter traits, right? Single-parameter traits
(i.e. only dependent on one type) probably cover about 90% of the use
cases but not all, for instance comparison or binary mathematical
operations are multi-parameter. I think, if interfaces/traits make it
into Base, they should be multi-parameter as single-parameter would be
at odds with multiple dispatch.

If I remember our conversation correctly, one of your main qualms with
Traits.jl are the trait-functions and their confusing syntax. Currently
they look like:

@traitfn f{X; Iterable{X}}(x::X) = ...
@traitfn g{X, Y; Eq{X,Y}}(x::X, y::Y) = ...

If traits make in into Base and *if* subtyping is removed, then (I
think) above could use the following syntax:

f(x::Iterable) = ...
g{Eq{X,Y}}(x::X, y::Y) = ...

So, the simpler syntax, as used in Interfaces.jl, could probably be used
for single-parameter traits. The `;` in the `{}` (separating types and
traits) could probably be removed. Although I haven't thought this
through yet, in particular how this meshes with diagonal and triangular
dispatch syntax.

A few more comments:

- You use some kind of mutable Unions. However, Unions in Julia are
immutable, I suspect for a reason. I don't know whether that could
lead to problems, maybe someone more knowledgeable can comment on
this?

- With your syntax, it is not clear from the the function signature
whether it's a type assertion or an interface assertion. But maybe it
doesn't need to be clear. Also a naming-convention could help, I
thought that traits could all start with Is* or Has*, like IsCallable
or HasLength.

- I think there is potential to share code between Interfaces.jl and
Traits.jl. In particular for the interface verification, where
methods signatures are compared. If you're interested I could try and
factor this out.

Mauro

On Tue, 2015-07-07 at 22:23, Rory Finnegan <rory.f...@gmail.com> wrote:
> I'll just mention Interfaces.jl
> <https://github.com/Rory-Finnegan/Interfaces.jl> as an alternative to

Rory Finnegan

unread,
Jul 8, 2015, 10:59:17 AM7/8/15
to juli...@googlegroups.com
Hi Scott, while I do agree that julia should have more than 1 way to solve a problem, I'm inclined to agree with python's philosophy that there is usually a better choice for a given situation (ie: some times it makes sense to take a functional approach and other times you should use a traditional OO pattern). Currently abstract types, traits and interfaces are all overlap a lot, so we probably need to mix at match what we like from each or refactor all of them to serve a very specific role. For example, I'd be happy if we got to a point where we could say, "You should use traits in cases like a, b, c and you should use interfaces in cases like x, y, z." Hopefully that makes sense :)

Hi Mauro,

Yeah, I'm not handling multiple parameters directly right now. You could support it by ensuring that all implementing types that get added to the interface union have the same number of parameters. The function definitions that use multiple parameters should already be validated as part of the implements call, but I haven't tested that. I'm going to make an issue for this, just to look at how hard it would be to have `@implements` enforce this.

I'd like to see the syntax differences between interfaces and traits get merged. Honestly, my main reason for having a separate package for this is just to prototype a different syntax without being biased by how the Traits.jl internals already work. When we talked before I got the impression I was having difficulty articulating how I would like it to work and I feel like a working example is easier to explain and play with.

So, yeah, we had to play around with some C code to get our slightly clunky mutable unions. I haven't been noticing any problems in terms of a memory leak or anything, but I guess there could be an optimization issue where the JIT can't reason about functions that take the mutable union type vs an immutable union type. It is also possible that the union type was initially made immutable cause under normal circumstances you'd have no reason to need to update it, so why support mutability if you don't have to.

I'm not sure I know what you mean by a type assertion vs an interface assertion, but I think it is an interface assertion. As in the function signatures are just saying any type that wants to implement this interface must have these methods defined (including the specific parameter types).

I agree. I think it might be kind of fun to put our shared components like comparing method signatures, parsing macro expression etc into a common repo, both to minimize duplicate code and possibly to promote other folks in the community playing around with different approaches to the interfaces/traits issue.

Cheers,
Rory

Scott Jones

unread,
Jul 8, 2015, 5:27:17 PM7/8/15
to juli...@googlegroups.com


On Wednesday, July 8, 2015 at 10:59:17 AM UTC-4, Rory Finnegan wrote:
Hi Scott, while I do agree that julia should have more than 1 way to solve a problem, I'm inclined to agree with python's philosophy that there is usually a better choice for a given situation (ie: some times it makes sense to take a functional approach and other times you should use a traditional OO pattern). Currently abstract types, traits and interfaces are all overlap a lot, so we probably need to mix at match what we like from each or refactor all of them to serve a very specific role. For example, I'd be happy if we got to a point where we could say, "You should use traits in cases like a, b, c and you should use interfaces in cases like x, y, z." Hopefully that makes sense :)

I agree totally.   I never said that the choice wasn't dependent on the situation.   What I've seen come up a number of times here is that people should follow the "one true way", and that support for other programming styles should not even be put into the language.
That seems rather at odds with the "we're all adults" philosophy that has also been espoused.

BTW, I think it would be great if you and Mauro can figure out whatever commonalities there are, and come up with something that it hopefully even better for everybody.

-Scott
Reply all
Reply to author
Forward
0 new messages