# \[ANN\] BinaryTraits.jl - a new traits package

**URL:** <https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475>\
**Category:** Package Announcements\
**Tags:** package, announcement, traits\
**Created:** [April 13, 2020, 12:01am UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475 "2020-04-13T00:01:08Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![tk3369](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tk3369/32/2824_2.png) [@tk3369](https://discourse.julialang.org/u/tk3369)\
**Post date:** [April 13, 2020, 12:01am UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/1 "2020-04-13T00:01:08Z")

</div>

Hi everyone,

I would like to announce [BinaryTraits.jl](https://github.com/tk3369/BinaryTraits.jl), a new traits package that focuses on usability and interface specification. You can find [documentation](https://tk3369.github.io/BinaryTraits.jl/dev/) from the project repo as usual. In addition, I have provided some examples for the standard [Iteration/Indexing and AbstractArray interfaces](https://github.com/tk3369/BinaryTraits.jl/tree/master/examples) in the examples folder.

# Why another package?

Julia’s traits story has been slowly developing over the past several years. There is nothing official in the language but several people attempted to experiment new ideas about how to make that work. Meanwhile, the [Holy Traits pattern](https://ahsmart.com/pub/holy-traits-design-patterns-and-best-practice-book.html) is mostly used given that it requires no additional package dependency.

However, I am not personally not satisfied because implementing Holy Traits requires quite a bit of code. [SimpleTraits.jl](https://github.com/mauro3/SimpleTraits.jl) does look very nice but I’m quite intimidated by its syntax/design. So, I end up developing a package that I think it should be **easy to use** and provide additional functionalities such as **formally specifying interface contracts** and **validating those contracts**.

# What can it do?

- Define traits and assigning them to your own data types
- Define composite traits that exhibits all of the underlying traits
- Define interface contracts for a trait
- Check if your data type fully implements all interface contracts

# Try it out! 🙂

This package is still in its early stage. I have been messing with the API several times in the past week. I would be pleased to receive any feedback and ideas for improving this package. You can either reply to this post or just submit an issue to my github repo.

The package is being registered at the moment. It will take 3 days due to the mandatory waiting period. But, I am so excited that I am sharing with you about the news now!

_-Tom_

## 🎉 🎉 🎉 Update 2020-04-20 (version 0.2.0)

I just tagged a new version after making some significant code changes and taking several very generous PRs from @klacru 🙂 Most improvements relate to the interface contracts specification and verification:

1. Interface contracts can now be specified with keyword arguments & complex argument types. Duck typed arguments are supported as well.

2. Interface contracts are now propagated to sub-traits for composite traits. Let’s say an abstract type `Bird` has `CanFly` trait, which requires a `fly` method per interface contract. Then all subtypes of `Birds` are required to implement the same contract.

P.S. More ideas and upcoming enhancements are logged in GitHub.

## 🎉 🎉 🎉 Update 2020-05-04 (version 0.3.0)

We had some breaking changes but they’re worth 100%.

1. The `@implement` macro now accepts an underscore argument, which indicates where the object argument should be passed for that function.

2. Traits defined from one module can now be referenced/used from another module. This would be useful for framework providers to define traits that implementations should follow.

See [updated documentation](https://tk3369.github.io/BinaryTraits.jl/dev/) for details.

## 🎉 🎉 🎉 Update 2020-05-17 (version 0.4.0)

This release implements a new parametric type design to represent traits. The reason for the change is that the previous design feels too “magical” in the sense that custom types are defined with specific prefixes/suffixes. The new design feels more natural and Julian.

## 🎉 🎉 🎉 Update 2020-06-07 (version 0.5.0)

This release adds return type check for interface contracts. Return type of an interface contract is covariant i.e. the implementation must return an object of a type that is a subtype of the required return type as specified in the contract. See [updated documentation about variance](https://tk3369.github.io/BinaryTraits.jl/dev/guide/#Variance-1) for more details.

---

<div class="post-metadata">

**Author:** ![Zach\_Christensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zach_christensen/32/7220_2.png) [@Zach\_Christensen](https://discourse.julialang.org/u/Zach_Christensen)\
**Post date:** [April 13, 2020, 12:17am UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/2 "2020-04-13T00:17:56Z")

</div>

I really enjoyed the “tickle” example

---

<div class="post-metadata">

**Author:** ![bcmichael](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bcmichael/32/10003_2.png) [@bcmichael](https://discourse.julialang.org/u/bcmichael)\
**Post date:** [April 13, 2020, 1:39am UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/3 "2020-04-13T01:39:26Z")

</div>

That looks really neat. I have a couple questions about the API for the interface contracts. It seems like with this design they aren’t really enforced contracts. If I understand correctly you can assign a trait to a type that doesn’t fully implement the associated interface, and the only way to tell whether they actually do implement it is with the check function. Have you considered checking whether the interface is implemented when you assign the trait, and rejecting the assignment if it isn’t?

My other question is about how you add required functions to the interface. First the trait is created and then separately functions are added to it. This means that in principle anyone can add functions to that interface at any point. I would think that in practice you would probably want to define the whole interface and then anyone wanting to extend it should probably use your composite traits to create a new extended interface. Do you think it would be possible or desirable to force the interface to be defined fully in one place along with the creation of the trait?

---

<div class="post-metadata">

**Author:** ![tk3369](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tk3369/32/2824_2.png) [@tk3369](https://discourse.julialang.org/u/tk3369)\
**Post date:** [April 13, 2020, 2:23am UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/4 "2020-04-13T02:23:00Z")

</div>

Great questions!

Julia, being a dynamic language, would be impossible to truly enforce anything statically. My thought is that you can put call the `check` function in your module’s ` __init__ ` function so everything is validated before you start using the package.

> [@bcmichael](#):
>
> Have you considered checking whether the interface is implemented when you assign the trait, and rejecting the assignment if it isn’t?

Doing the check when you `@assign` a type sounds like an interesting idea although it would require you to define all functions before assigning traits. It might be a little unnatural as you would have to order your code in a certain way.

> [@bcmichael](#):
>
> My other question is about how you add required functions to the interface. First the trait is created and then separately functions are added to it. This means that in principle anyone can add functions to that interface at any point. I would think that in practice you would probably want to define the whole interface and then anyone wanting to extend it should probably use your composite traits to create a new extended interface. Do you think it would be possible or desirable to force the interface to be defined fully in one place along with the creation of the trait?

Yes, I would image the the interface designer would do the following:

1. Define the trait using `@trait` macro
2. Define the generic functions as related to the interface (no need to have any method body)
3. Specify the requirements using `@implement` macro

Then, as a user implementing the interface, I would do the following:

1. Define my data type
2. Extend the required functions
3. Perform a `check` to make sure that I’ve done everything properly

Does that make sense?

---

<div class="post-metadata">

**Author:** ![bcmichael](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bcmichael/32/10003_2.png) [@bcmichael](https://discourse.julialang.org/u/bcmichael)\
**Post date:** [April 13, 2020, 2:55am UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/5 "2020-04-13T02:55:12Z")

</div>

Yeah that makes sense. I was suggesting something more like the following:

Interface designer:

1. Define the generic functions related to the interface
2. Use a single macro to define the trait and specify all of the functions of the interface

Implementer:

1. Define the type
2. Extend the functions
3. Assign the trait (and get an error if all of the functions aren’t extended)

The advantages I see to this would be that the API no longer gives a way to add functions to the interface from anywhere in the code other than where the interface is defined, which I think is not something you would really want people to do. Additionally you don’t have to manually check whether you implemented everything properly, because the API just throws an error when you go to apply the trait if you didn’t.

Obviously you can’t actually stop anyone from messing with the internals and applying traits to things that don’t meet the interface requirements or adding more functions to the interface, but the API could not provide a convenient way to do so.

---

<div class="post-metadata">

**Author:** ![tk3369](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tk3369/32/2824_2.png) [@tk3369](https://discourse.julialang.org/u/tk3369)\
**Post date:** [April 13, 2020, 3:13am UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/6 "2020-04-13T03:13:09Z")

</div>

That’s a really neat idea. Thank you. It’s going to my “try that out next” queue 🙂

---

<div class="post-metadata">

**Author:** ![affans](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/affans/32/11911_2.png) [@affans](https://discourse.julialang.org/u/affans)\
**Post date:** [April 13, 2020, 3:13am UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/7 "2020-04-13T03:13:14Z")

</div>

Can someone give a basic definition and a base use case for what traits are? I have tried to understand `SimpleTraits`, but didn’t really understand _why_ such a package would be needed? I feel like most of the examples can be done with “regular” Julia.

---

<div class="post-metadata">

**Author:** ![tk3369](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tk3369/32/2824_2.png) [@tk3369](https://discourse.julialang.org/u/tk3369)\
**Post date:** [April 13, 2020, 3:25am UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/8 "2020-04-13T03:25:52Z")

</div>

A trait represents certain characteristics of an object.

For example, if you have implemented a container that supports indexing e.g. `myobject[3]` for accessing the 3rd element in your container, then any code that uses your object can extract an element using the [indexing interface](https://docs.julialang.org/en/v1/manual/interfaces/#Indexing-1).

But, how do you know the object supports the indexing interface? So it would be nice to “attach” the type of your object to a trait type. Further, it would be nice to also associate the trait type with required interface functions. BinaryTraits.jl solves the problem by giving you such capability. You can review an [iteration/indexing example](https://github.com/tk3369/BinaryTraits.jl/blob/master/examples/iteration_indexing.jl#L35-L36) that is borrowed directly from the Julia manual.

Using Holy Traits, you are being explicit about what your code is doing. Rather than assuming that the object supports indexing interface, you first check if the object exhibits the indexing trait and if so you can dispatch to the function that uses the indexing function.

Hope it helps!

---

<div class="post-metadata">

**Author:** ![klacru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klacru/32/27890_2.png) [@klacru](https://discourse.julialang.org/u/klacru)\
**Post date:** [April 13, 2020, 11:11am UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/9 "2020-04-13T11:11:51Z")

</div>

Excellent work! I tried it out immediately. would you mind if I entered some suggestions as issues in the repository?  
I found some missing features in the `implement` macro I would like to add:

1. the argument requires to specify an argument type for each argument - could default to `Any`
2. the specified argument type needs to be simple, for example no type parameter allowed
3. keyword arguments are not supported

---

<div class="post-metadata">

**Author:** ![roble](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roble/32/12303_2.png) [@roble](https://discourse.julialang.org/u/roble)\
**Post date:** [April 13, 2020, 1:13pm UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/10 "2020-04-13T13:13:04Z")

</div>

Hi Tom, first I would like to thank you for creating such a nice package.

The Idea of using traits on abstract types somehow reminds me of `interface classes` in Java. However with Julias “limitation” of single inheritance, I was wondering whether inheriting traits from multiple abstract types would be possible.

Do you know how you could achieve this?

---

<div class="post-metadata">

**Author:** ![tk3369](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tk3369/32/2824_2.png) [@tk3369](https://discourse.julialang.org/u/tk3369)\
**Post date:** [April 13, 2020, 3:04pm UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/11 "2020-04-13T15:04:52Z")

</div>

Hi @klacru,

> [@klacru](#):
>
> would you mind if I entered some suggestions as issues in the repository?

Not at all. Please do enter them as separate issues so we can further discuss and work on them independently. In fact, PR’s are welcome as well.

> [@klacru](#):
>
> - the argument requires to specify an argument type for each argument - could default to `Any`

Yes, but I am unsure if `Any` is the right default. When I tried to use it with the `AbstractArray` interface, which uses duck typing in the interface, I figured that I need to use `Base.Bottom` instead. See the [LinearIndexing trait example](https://github.com/tk3369/BinaryTraits.jl/blob/06e8ce359e6939643762c182361720f785654c1d/examples/abstract_array.jl#L16-L18). If we want to impose a default then I think `Bottom` is more appropriate because otherwise the implementer must define the function that accepts explicitly `Any`.

> [@klacru](#):
>
> the specified argument type needs to be simple, for example no type parameter allowed

Right, I realized the missing feature as well. Currently, it needs to be a simple “symbol” for the parser to work. I guess it’s less convenient but you can define a constant and then use it in the interface. See the [CartesianIndexing trait example](https://github.com/tk3369/BinaryTraits.jl/blob/06e8ce359e6939643762c182361720f785654c1d/examples/abstract_array.jl#L20-L24).

> [@klacru](#):
>
> keyword arguments are not supported

This is actually a limitation with Julia itself because keyword arguments are not considered for dispatch. I also wonder how useful it would be… Can you share a use case for this if you happen to have one?

---

<div class="post-metadata">

**Author:** ![klacru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klacru/32/27890_2.png) [@klacru](https://discourse.julialang.org/u/klacru)\
**Post date:** [April 13, 2020, 3:10pm UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/12 "2020-04-13T15:10:43Z")

</div>

I will transfer my points and your replies into issues - see you there.

---

<div class="post-metadata">

**Author:** ![tk3369](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tk3369/32/2824_2.png) [@tk3369](https://discourse.julialang.org/u/tk3369)\
**Post date:** [April 13, 2020, 3:15pm UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/13 "2020-04-13T15:15:16Z")

</div>

Hi @roble,

In Java, interface was originally designed to overcome the lack of multiple inheritance.  
Similarly, BinaryTraits supports the notion of composite traits which roughly gives you the same thing as multiple inheritance (with the exception of not being able to inherit memory layout – a conscious design decision for abstract types in the Julia language).

Let’s take [the multiple interface example from freeCodeCamp](https://www.freecodecamp.org/forum/t/java-interfaces-explained-with-examples/16726). We can implement the same thing here as follows:

```julia
@trait GPS
@implement GPS by get_coordinates()

@trait Radio
@implement Radio by start_radio()
@implement Radio by stop_radio()

struct SmartPhone end
get_coordinates(phone::SmartPhone) = ...
start_radio(phone::SmartPhone) = ...
stop_radio(phone::SmartPhone) = ...

```

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [April 13, 2020, 6:02pm UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/14 "2020-04-13T18:02:00Z")

</div>

How much of this resolves at compile time?

---

<div class="post-metadata">

**Author:** ![affans](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/affans/32/11911_2.png) [@affans](https://discourse.julialang.org/u/affans)\
**Post date:** [April 13, 2020, 6:02pm UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/15 "2020-04-13T18:02:39Z")

</div>

So traits are really for developers rather than end users… For example, for scientists who use Julia for exploratory analysis really have no need for this right?

Developers of packages, however, may find it useful to see if they’ve implemented the interface correctly. So even developers are “end users” of this package. Using your example of `Squares`. If I was implemented `Squares`, I’d basically have to run the `check()` function to see if I’ve implemented the interface correctly. Ultimately, it would have to be Julia developers to implement traits on the actual `Iterators` interface (so that I, as a package developer, can use the `check` function)

Does my interpretation make sense?

---

<div class="post-metadata">

**Author:** ![tk3369](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tk3369/32/2824_2.png) [@tk3369](https://discourse.julialang.org/u/tk3369)\
**Post date:** [April 13, 2020, 6:37pm UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/16 "2020-04-13T18:37:07Z")

</div>

@JeffreySarnoff I would expect everything to be resolved at compile time. They are just convenient macros to implement Holy Traits.

---

<div class="post-metadata">

**Author:** ![tk3369](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tk3369/32/2824_2.png) [@tk3369](https://discourse.julialang.org/u/tk3369)\
**Post date:** [April 13, 2020, 6:40pm UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/17 "2020-04-13T18:40:29Z")

</div>

That sounds right. I would guess that most end users care more about getting things done than coming up with the best design for their code. There are more advanced users though. I would think that people who are proficient in designing data types and integrating with other packages will be the primary users of traits.

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [April 13, 2020, 7:24pm UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/18 "2020-04-13T19:24:28Z")

</div>

If packages expose their use via traits, then even the users of packages must be aware of how to use traits. Isn’t that right?

---

<div class="post-metadata">

**Author:** ![tk3369](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tk3369/32/2824_2.png) [@tk3369](https://discourse.julialang.org/u/tk3369)\
**Post date:** [April 13, 2020, 7:58pm UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/19 "2020-04-13T19:58:38Z")

</div>

That’s true if a package expects users to be the implementer of certain interfaces then end users would that have do that. It should be easy to implement traits - most likely just reading documentation to find out how to satisfy interface requirements by implementing certain functions.

---

<div class="post-metadata">

**Author:** ![tk3369](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tk3369/32/2824_2.png) [@tk3369](https://discourse.julialang.org/u/tk3369)\
**Post date:** [May 5, 2020, 6:23am UTC](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475/20 "2020-05-05T06:23:26Z")

</div>

Just FYI - I just tagged a new release 0.3.0. See the [first post](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475) above for a quick summary or just hit our [BinaryTraits.jl project page](https://github.com/tk3369/BinaryTraits.jl).

[Next page](https://discourse.julialang.org/t/ann-binarytraits-jl-a-new-traits-package/37475.md?page=2)
