Trying to understand Protocols vs Behaviours

1647 views
Skip to first unread message

Ed W

unread,
Apr 13, 2015, 11:58:33 AM4/13/15
to elixir-l...@googlegroups.com
I'm trying to get my head around why we need both Protocols and
Behaviours? I think I understand the basic features and motivation of
each, but I don't see a requirement for both (I'm expecting the answer
to be performance?)

Behaviours:
- Act a little like "interfaces" in OO language
- Ensure a module meets a contract on function implementations
- Offers no native polymorphism implementation, therefore somewhat
useless *without* adding a macro overlay to implement some kind of
Polymorphism type behaviour on top of them!! (Presumably Protocols are
implemented using Behaviours and largely Behaviours exist as an inner
implementation of Protocols?)

Protocols:
- Act much more like polymorphism interfaces in an OO language
- Allow us to implement a contract interface on specific datatypes (note
we don't have module level scope of implementation unless the module
happens to be a struct/map datatype)
- Appears to be useful as a standardised polymorphism mechanism!
- Appears to have performance concerns? Are these only relevant in
development mode before consolidation?


Whilst I understand that Behaviours might be one of the underlying
pieces used to implement Protocols, what I don't understand is why I
would use one generally? I don't see that they intrinsically offer any
polymorphic advantage without some sort of layer over the top?

To clarify, the Elixir documentation shows we can build a JSONParser and
a YAMLParser with exactly the same function names implemented. However,
I don't see how this *alone* is terribly useful? I still need to
specify the Module.Function I am using on a given datatype, so in the
absence of some further polymorphic magic I will always need to use some
conditional code path to detect the datatype passed to me and call
either JSONParser.parse or YAMLParser.parse ?

Protocols appear to implemented the expected polymorphism, ie I can
implement something like "ConfigParser.parse" and implement that for
both the JSON and YAML "types". I can also easily see a number of ways
I could implement my own hand-rolled polymorphism alike structures and
indeed it would be very helpful to have Behaviours as the building
blocks for those. So yes I do see why Behaviours are useful, BUT, only
as the building blocks for higher level polymorphism alike structures?

Is my understanding of the relationship between Behaviours/Protocols
correct?


Q: Why isn't more of Elixir implemented in protocols?
Is it performance related?

Q: Why aren't Set and Dict implemented using protocols?
Is it because of performance issues in development mode? Does the
performance of Protocols become equal to the current implementation in
release mode after consolidation?

It seems that current implementations of Set and Dict are implemented
using a kind of hand-rolled polymorphism. My understanding is that this
will be somewhat similar to the effect of using a Protocol, but with
some implementation limitations and requiring a different method to
implement a new Set/Dict type?

The current implementation seems to somewhat handicap implementing say
new Dict types? For example if I had invented some new fancy key value
datastore structure, then were Dict a protocol I would simply implement
the required protocol functions and now I could pass the new datatype in
to any function expecting a Dict type and off we go.

However, right now there is probably a bunch of code written using
"HashDict.xxx" and to use my new datatype I guess I would need to
implement a new implementation CleverNewDict, and then update any
HashDict references (or hopefully the user used Dict.xxx instead?). This
feels like it would hinder implementation of drop in replacements for
Dict right now? Do we care?



Pointy end of the question:
I implemented a Priority Queue in Elixir as a learning exercise:
https://github.com/ewildgoose/elixir_priority_queue

The Priority Queue implementation requires a Heap datatype to operate. I
would like to standardise that Heap datatype so that I can experiment
with performance using different underlying Heap implementations. I
seem to have two ways I might proceed:

- Using a Protocol for my Heap. I would define my required
implementation and then very flexibly I could drop in any old module
which behaves something like a Heap. eg It might make sense to use
something wrapping Redis for certain use distributed cases, it might be
be better to use a native datastructure for others. In no case will the
PQ algorithm need to know. Also any user can implement the protocol
between PQ and some potential datastructure, without needing to open the
implementation of either.

- Use Dict/Set as an implementation guideline. This involves writing a
behaviour for the Heap interface, and offering polymorphic dispatch by
implementing dispatch through implementation of a "target()" macro in
the Heap module. I found this quite tricky to understand when first
reading the code and it seems to hinder implementing new Heap types
(requires the implementer to comply with *my* polymorphism
implementation and the new candidate module must be opened and modified
to work in a certain way, ie we require access to the candidate module
code (or wrap it))


Given I specify that performance is vital, does this mean I should
choose the Dict/Set type (hand rolled) polymorphism? Is the more
general answer: "Use Protocols whenever you can, but if performance is
vital then use a handrolled polymorphism based on the Dict/Set style
implementation"?


Sorry, this got away from me and is rather long winded. Grateful if
anyone reads this far and takes the time for a considered answer? I
don't see much real world use of Protocols (to copy) and most of the
Elixir codebase seems to use various tricks to avoid the use of Protocols?

Thanks

Ed W

José Valim

unread,
Apr 13, 2015, 12:16:49 PM4/13/15
to elixir-l...@googlegroups.com
A protocol is indeed a behaviour + dispatching logic.

However I think you are missing the point of behaviours. Behaviours are extremely useful. For example, a GenServer defines a behaviour. A behaviour is a way to say: give me a module as argument and I will invoke the following callbacks on it, which these argument and so on. A more complex example for behaviours besides a GenServer are the Ecto adapters.

However, this does not work if you have a data structure and you want to dispatch based on the data structure. Hence protocols.

> Q: Why isn't more of Elixir implemented in protocols?

Because we have not identified more protocols. One could say: we could make +, - and so on all based on protocols however I don't think protocols should be the default. They should be opt-in both when defining and when invoking because I prefer my code to be assertive than generic. I wrote a little bit about it here: http://blog.plataformatec.com.br/2014/09/writing-assertive-code-with-elixir/

> Q: Why aren't Set and Dict implemented using protocols. Is it because of performance issues in development mode? Does the performance of Protocols become equal to the current implementation in release mode after consolidation?

Partially yes and yes, respectively.

For the first question, besides the performance concern, I think large protocols are a smell and you can't efficiently implement a dictionary with a small set of functions. So in order to not open up a precedent for large protocols in Elixir and solve the performance issues, we have decided with the current implementation.

However, once consolidated, protocols are as fast as the hand-rolled functions in the Dict module.

> However, right now there is probably a bunch of code written using "HashDict.xxx" and to use my new datatype I guess I would need to implement a new implementation CleverNewDict, and then update any HashDict references (or hopefully the user used Dict.xxx instead?). This feels like it would hinder implementation of drop in replacements for Dict right now? Do we care?

Not sure I follow. Can't you use the Dict module if you want it to be generic?

José Valim
Skype: jv.ptec
Founder and Lead Developer



Ed W

--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-talk+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-talk/552BE7A7.6060505%40wildgooses.com.
For more options, visit https://groups.google.com/d/optout.

Ed W

unread,
Apr 14, 2015, 6:05:47 AM4/14/15
to elixir-l...@googlegroups.com
Hi José, thanks for taking the time to read and respond, appreciated.  Please forgive if my words below come over as being overly challenging, I'm just trying to draw you out on what feels like an important style concept in Elixir.


On 13/04/2015 17:16, José Valim wrote:
However I think you are missing the point of behaviours. Behaviours are extremely useful. For example, a GenServer defines a behaviour. A behaviour is a way to say: give me a module as argument and I will invoke the following callbacks on it, which these argument and so on. A more complex example for behaviours besides a GenServer are the Ecto adapters.

Hmm, interesting, I hadn't considered that this style of "polymorphism" is quite standard in Erlang. Thankyou



However, this does not work if you have a data structure and you want to dispatch based on the data structure. Hence protocols.

Hmm, see I'm still not getting the (practical) difference I'm afraid

I see your comment as correct in as much as we *could* dispatch based on data structures *if* everyone who wrote a datastructure agreed on a common contract for the function names and meaning and implemented their datastructures with those contracts in mind (ie this is just what we do with a "behaviour") - clearly this rarely happens, hence the need for protocols?

But I understand the cleverness of protocols to be that the "interface glue", ie the dispatching logic is effectively allowed to be in a third module and not in either the data structure or the calling module.  This is definitely extremely clever and inciteful (congratulations)

But for practical purposes I don't see that a behaviour is any different to a protocol, other than a behaviour *forces* the glue logic into the datastructure module, rather than allowing it to live outside that module, as with a protocol?



> Q: Why isn't more of Elixir implemented in protocols?

Because we have not identified more protocols. One could say: we could make +, - and so on all based on protocols however I don't think protocols should be the default. They should be opt-in both when defining and when invoking because I prefer my code to be assertive than generic. I wrote a little bit about it here: http://blog.plataformatec.com.br/2014/09/writing-assertive-code-with-elixir/

Thankyou, I read your article previously, but I just read it again in the light of your response and I understand your point much more clearly.  I guess I don't understand what problem you perceive in allowing polymorphism to permeate easily in order to disagree?  I dare say it's a good point of view, but perhaps you have capacity to discuss further what problems you see with opening the floodgates to protocols?  I think this is an important opinion for you to express because it should shape the way newcomers (like myself) try to make use of this language? (Remember many new users will come from Ruby where the expectation is quite the opposite and "quacks-like-a" is quite the norm?)

Can I recommend then that this is quite a core point to get across. Also it would seem sensible to document and encourage some standardisation in this alternative form of "polymorphism" that you are encouraging in elixir core.  So I realise it probably looks very simple to yourself, but I did have to read the Dict/Map implementation several times before I understood how the two modules interact.  If this is a good style guide then I think we should perhaps explain it a little more and promote it?


My naive opinion would be that Set and Dict are great examples of Protocols...  Forgive me that I quite like Perl, and so to my eye every datastructure wants a Dict interface...

I'm looking at the Dict code right now.  To make my random datatype pretend to be a Dict I need to implement:

* delete/2
* fetch/2
* put/3
* reduce/3
* size/1

To my eye this is just crying out to be a Protocol? I can then trivially turn any datastructure into a "Dict" and of course I get to keep all the pieces and the responsibility for ensuring this works out... 

Why am I wrong?


> Q: Why aren't Set and Dict implemented using protocols. Is it because of performance issues in development mode? Does the performance of Protocols become equal to the current implementation in release mode after consolidation?

Partially yes and yes, respectively.

For the first question, besides the performance concern, I think large protocols are a smell and you can't efficiently implement a dictionary with a small set of functions. So in order to not open up a precedent for large protocols in Elixir and solve the performance issues, we have decided with the current implementation.

But this is where I still struggle to understand your point?

Firstly I would be interested in why you consider protocols to be a smell?  I can't disagree because I'm not sure I see the problem (assume I get the extreme cases, it's the middle ground I don't understand)

Secondly I don't see why you need to implement only a small set of functions as a protocol?  To clarify that question:
- The current implementation is no different to a protocol, only by using a behaviour you force any Dict implementation (say FastDict) to include the interface definitions *within* the FastDict module itself.  If the current behaviour were turned into a protocol then I would be free to take any datastructure and implement the protocol for it, neither the Dict nor the datatype would need to know I was doing that.  So fundamentally I see no difference, OTHER, than the current use of behaviour requires a much more integrated implementation?

- Additionally I don't see the problem with splitting up protocols. If the protocol is too large then probably its trying to be decomposed into a core protocol and a secondary protocol?


I think the core of my misunderstanding is that:
- I'm implementing some new datatype
- It's not really a Dict, but I feel I would like to make it accessible through a Dict type interface
- At present that means *I* (the module owner) need to commit and implement the behaviour inside my datatype, I can't choose to implement it as a third party user of the module (or perhaps I can?? How?)



> However, right now there is probably a bunch of code written using "HashDict.xxx" and to use my new datatype I guess I would need to implement a new implementation CleverNewDict, and then update any HashDict references (or hopefully the user used Dict.xxx instead?). This feels like it would hinder implementation of drop in replacements for Dict right now? Do we care?

Not sure I follow. Can't you use the Dict module if you want it to be generic?

My point is that probably the author already used the SpecificModule rather than the generic module.  You seem to be advocating using specific implementations rather than the generic implementation?

So, say my code uses Map everywhere, then I realise there are performance constraints on that, and someone tells me I can use FastMap instead to get around that.  I now realise that to make this change requires a) a code change (ie I need to own the code) and b) some search and replace changes.  Had I used the generic modules I would be in a better place (or would I?)

I guess I'm trying to find examples where polymorphism wins, and hoping you will tell me why I'm wrong or what pitfalls I will hit by flowing in the other direction?



Can I ask you to comment on this below then?  I think what you are confirming is that *your* opinion would be I should use the behaviour based "polymorphism-alike" that is used in the Dict/Set implementations in Elixir core?

Pointy end of the question:
I implemented a Priority Queue in Elixir as a learning exercise:
    https://github.com/ewildgoose/elixir_priority_queue

The Priority Queue implementation requires a Heap datatype to operate. I would like to standardise that Heap datatype so that I can experiment with performance using different underlying Heap implementations.  I seem to have two ways I might proceed:

- Using a Protocol for my Heap.  I would define my required implementation and then very flexibly I could drop in any old module which behaves something like a Heap. eg It might make sense to use something wrapping Redis for certain use distributed cases, it might be be better to use a native datastructure for others. In no case will the PQ algorithm need to know. Also any user can implement the protocol between PQ and some potential datastructure, without needing to open the implementation of either.

- Use Dict/Set as an implementation guideline.  This involves writing a behaviour for the Heap interface, and offering polymorphic dispatch by implementing dispatch through implementation of a "target()" macro in the Heap module.  I found this quite tricky to understand when first reading the code and it seems to hinder implementing new Heap types (requires the implementer to comply with *my* polymorphism implementation and the new candidate module must be opened and modified to work in a certain way, ie we require access to the candidate module code (or wrap it))


Given I specify that performance is vital, does this mean I should choose the Dict/Set type (hand rolled) polymorphism?  Is the more general answer: "Use Protocols whenever you can, but if performance is vital then use a handrolled polymorphism based on the Dict/Set style implementation"?


Finding Elixir very interesting, but as with all languages, once you get beyond learning the syntax there is a much longer path to working *with* the language style

Thanks for creating Elixir!

Ed W

José Valim

unread,
Apr 14, 2015, 7:05:36 AM4/14/15
to elixir-l...@googlegroups.com
I see your comment as correct in as much as we *could* dispatch based on data structures *if* everyone who wrote a datastructure agreed on a common contract for the function names and meaning and implemented their datastructures with those contracts in mind (ie this is just what we do with a "behaviour") - clearly this rarely happens, hence the need for protocols?

Pretty much, yes. Also we have a lot of cross-cutting concerns. Imagine someone implements a new dictionary, should it include the JSON rendering logic for all 5 to 10 available JSON libraries?
 
But for practical purposes I don't see that a behaviour is any different to a protocol, other than a behaviour *forces* the glue logic into the datastructure module, rather than allowing it to live outside that module, as with a protocol?

Yes, precisely. Protocol is a behaviour with the dispatching logic so you don't need to hand roll it nor impose a particular implementation in the user module.

I guess I don't understand what problem you perceive in allowing polymorphism to permeate easily in order to disagree?

Because with protocols my code becomes less assertive and therefore harder to understand. When I see to_string(data), I have no idea what data is. Up to that point, my brain keeps a blank space with the information that is must implement String.Chars. However, if I see Atom.to_string/1, I know exactly what it should be.

So I optimize first for readability and understanding of the code. Polymorphism is very handy but it should be opt-in.

Just as an anecdote: protocols provide the same sort of polymorphism as Haskell type classes. During the panel at Erlang Factory, John Hughes commented that, after they added type classes to Haskell, they started to implement *everything* with type classes and that eventually messed up the type checker because it had no reference point. All code was generic!

I believe the same process happens with our brain. Once the code is too generic, it is harder to understand and reason about it because we don't have any reference point, we end-up working with a lot of "maybe"s.

(Remember many new users will come from Ruby where the expectation is quite the opposite and "quacks-like-a" is quite the norm?)

It is important to make a distinction that, not every time you are quacking-like something, you are defining an explicit contract.

For example, take a look at tests that use mocks. You are using a mock to quack-like some object but there is no explicit contract. If you change your code, you go and change your test. You also wouldn't define a protocol or behaviour for those cases in Elixir either.

Similarly, you don't want to say "quacks-like a string" because that would mean you have to implement more than 100 methods. What you want, most of the time, is to define tiny contracts, instead of saying quacks-like a whole object. And you want to abide to it and explicitly test this contract. However, because this contract is implicit in Ruby, you end-up violating it (by adding or removing functions to it) more often than not unless you make it explicit. I am not saying there aren't explicit & tiny contracts in Ruby, we definitely have some, a quick example being places that call .to_str.

So it is mostly a different mindset than the Ruby one. More explicit & tiny contract/protocols instead of implicit & ad-hoc duck typing. That is also the direction taken by Go, Clojure, Haskell and others.

As a reference, look how clean it is to integrate Ecto (a database layer) into Phoenix (web framework): https://github.com/phoenixframework/phoenix_ecto/tree/master/lib/phoenix_ecto

To my eye this is just crying out to be a Protocol? I can then trivially turn any datastructure into a "Dict" and of course I get to keep all the pieces and the responsibility for ensuring this works out...  

If we defined a Dict protocol, we had three options:

1. it would be too large in order to implement all functions efficiently
2. it would be too tiny, with just some functions, and therefore incomplete and less useful
3. it would be too tiny, with a set of primitives, which would make assumptions on all other Dict implementations possibly make all other operations slow. Yes, you can implement Dict.update as a get and put, but that requires accessing it twice. You would have trade-offs like these every other function.

That's why a protocol doesn't make sense. You would put yourself in any way into a corner.

Set and Dict are a special case where we don't want you to say "this data-structure behaves like a dictionary". Or it is a dictionary/set or it isn't.




José Valim
Skype: jv.ptec
Founder and Lead Developer

--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-talk/552CE675.40205%40wildgooses.com.

Saša Jurić

unread,
Apr 14, 2015, 8:59:36 AM4/14/15
to elixir-l...@googlegroups.com

But for practical purposes I don't see that a behaviour is any different to a protocol, other than a behaviour *forces* the glue logic into the datastructure module, rather than allowing it to live outside that module, as with a protocol?

I'm not even sure that behaviour qualifies as polymorphism, because it's not a data driven dispatch. You use the generic behaviour (e.g. GenServer), and make it concrete by providing your callback module - a plugin that is essentially a bunch of functions. The generic logic then drives the process and invokes the callback module when some concrete decisions need to be made.

Since behaviour is type agnostic, we can get some flexible properties. For example in GenServer:

- the same type (struct) can be used as the state of different concrete GenServers
- a single GenServer can easily mutate it's state into some other type at any point in time

This can surely be implemented with protocols as well, but I think the result would require more boilerplate on behalf of the client programmer.

So in my mind, a behaviour is more appropriate when the generic logic doesn't care about the data at all. It may take some data from the concrete implementation and return it later to that same implementation (which is exactly what GenServer does), but it doesn't perform any operations itself with that data.


Can I ask you to comment on this below then?  I think what you are confirming is that *your* opinion would be I should use the behaviour based "polymorphism-alike" that is used in the Dict/Set implementations in Elixir core?

In my opinion, if you want to vary Heap implementations, I think protocols are the initial way to go here, since you're doing a data based polymorphism. As José explained, there shouldn't be perf. penalty once you consolidate, so you should be fine.

Ed W

unread,
Apr 14, 2015, 11:08:06 AM4/14/15
to elixir-l...@googlegroups.com
On 14/04/2015 12:05, José Valim wrote:

I guess I don't understand what problem you perceive in allowing polymorphism to permeate easily in order to disagree?

Because with protocols my code becomes less assertive and therefore harder to understand. When I see to_string(data), I have no idea what data is. Up to that point, my brain keeps a blank space with the information that is must implement String.Chars. However, if I see Atom.to_string/1, I know exactly what it should be.

So I optimize first for readability and understanding of the code. Polymorphism is very handy but it should be opt-in.

I think we are talking cross purposes.  I kinda understand what you mean about adding "to_string", but in this case the author of the "to_string" code is going to be the person implementing the protocol to glue "SomeDataType" to the Dict protocol, so I don't think it needs to bother you in the slightest?

Because we are perhaps misunderstanding each other:
- I don't see that the current (Dict) code changes more than a tiny amount if it were to switch from a behaviour to a protocol?
- BUT, it would mean that *I* (not you) can then happily implement a Dict protocol for some *third party* datatype (ie that I didn't write)
- In this case neither the author of the datatype, nor the Elixir Dict implementation need to know what I'm up to, so any use of "to_string" is up to me to make it nice and clean, including any type coercion

I'm not sure why we are talking past each other here.  Today, right now, there *is* a form of polymorphism used to implement the Dict/Map modules.  ie calling Dict.update(dict,...), calls target(dict).update(dict,...) - much of what I'm asking is why not use protocol polymorphism rather than this "target(dict)" form of polymorphism?



If we defined a Dict protocol, we had three options:

1. it would be too large in order to implement all functions efficiently
2. it would be too tiny, with just some functions, and therefore incomplete and less useful
3. it would be too tiny, with a set of primitives, which would make assumptions on all other Dict implementations possibly make all other operations slow. Yes, you can implement Dict.update as a get and put, but that requires accessing it twice. You would have trade-offs like these every other function.

That's why a protocol doesn't make sense. You would put yourself in any way into a corner.

OK, so can I disagree if we talk specifically about Dict.  Here is a concrete proposal:

- Split the protocol into a core which must be implemented and a secondary which adds performance shortcuts
- A tight core protocol encourages thought about minimising the surface area of the API and neat implementations
- Tight core protocol will also encourage re-use by moving generic code up to default implementation


So the documentation for Dict says that the core protocol is simply

    * `delete/2`
    * `fetch/2`
    * `put/3`
    * `size/1`


This seems like a very tight core protocol already.  Also most of Dict is implemented generically, lets see what is implemented in practice. Specifically looking at Map the entire module can be abbreviated approx as follows (I have removed merge, could possibly remove has_key?):

  def size, do: maps.size(map)
  def has_key?(map, key), do: :maps.is_key(key, map)
  def fetch(map, key), do: :maps.find(key, map)
  def put(map, key, val), do: :maps.put(key, val, map)
  def delete(map, key), do: :maps.remove(key, map)
  def equal?(%{} = map1, %{} = map2), do: map1 === map2


So the core of the Map implementation is around 8 lines.  As such I'm not sure that I see a problem ref your perceived issues above? 

- With regards to 1) the API is the same size whether implemented as a single protocol or via the current behaviour+target() implementation.
- With regards to 2) the current API is specified as being 4 main functions to implement, with the remainder being implementable with a default implementation. This seems perfect, not too small?
- With regards to 3, I'm not sure there are currently great optimisations being implemented? I see perhaps HashDict.update, and Map.size looking like they might make a difference? 

With a protocol in mind comparing both current Dict implementations I see repetition and performance impact from
- Size
- Equal?

These seem like possible candidates for a new protocol? Implementing such would seem to significantly further reduce the two Dict implementations (Map/HashDict).


Just for kicks, here is the documentation for Perl on implementing tie'd hash/array, etc. We can use it to challenge our interface above and see if we are complete:
    http://perldoc.perl.org/functions/tie.html



So, how about:

Protocol: Size
Protocol: Equal?
Protocol Dict.Core
    delete/2
    fetch/2
    put/3
Protocol Dict.Optional
    rest of the current Dict


Thanks for listening

Ed W

José Valim

unread,
Apr 14, 2015, 11:15:28 AM4/14/15
to elixir-l...@googlegroups.com
I believe we are talking past each other a bit because it seems we are mixing two different topics? Is it about Behaviour vs Protocols or is it particularly about Dicts and changes to Dict? Most of my observations were general and not regarding the Dict module, unless otherwise explicitly said.

So if you would like to change the Dict module, can you please start another discussion with your proposals? Preferably on the elixir-lang-core mailing list?

Robert Virding

unread,
Apr 14, 2015, 11:31:04 AM4/14/15
to elixir-l...@googlegroups.com, jose....@plataformatec.com.br
One thing missing, or I might have just missed it, in the Behaviour vs Protocols discussion so far is that Behaviours are explicitly connected to processes. A Behaviour describes the basic behaviour (sorry for the pun) of a process and the API to access it and use it. They are intimately connected and you can not have an instance of a Behaviour without a process. This very much defines the context of a Behaviour.

While a Protocol could very much have processes internally they are not required in the same way as Behaviours. The examples of protocols so far aren't process based, though they could be but it would very much change the protocol.

Robert

Peter Hamilton

unread,
Apr 14, 2015, 12:21:21 PM4/14/15
to elixir-l...@googlegroups.com, jose....@plataformatec.com.br

Robert -
As cited in this thread, Dicts and Sets are simple data structures in Elixir that are implemented via a Behavior. The methods in those functions derive the module from the data structure passed in and dispatch accordingly. See https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/dict.ex

Let's move the discussion around Dict and Set to a separate thread specifically around those code changea. Regarding a minimal protocol and a full protocol, we already have a precedent with Enumerable.count/1 where there's a default implementation.


--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.

Ed W

unread,
Apr 14, 2015, 12:41:21 PM4/14/15
to elixir-l...@googlegroups.com
On 14/04/2015 16:15, José Valim wrote:
> I believe we are talking past each other a bit because it seems we are
> mixing two different topics? Is it about Behaviour vs Protocols or is
> it particularly about Dicts and changes to Dict? Most of my
> observations were general and not regarding the Dict module, unless
> otherwise explicitly said.

Understood. I didn't intend to come across that way, I was just trying
to use a specific example to try and draw you out on your opinion on
when a new coder should learn to use behaviour vs protocol



> So if you would like to change the Dict module, can you please start
> another discussion with your proposals? Preferably on the
> elixir-lang-core mailing list?

Understood. I will make a proposal there.

Thanks for taking the time to respond

Ed W

José Valim

unread,
Apr 14, 2015, 1:45:00 PM4/14/15
to elixir-l...@googlegroups.com
Understood.  I didn't intend to come across that way, I was just trying to use a specific example to try and draw you out on your opinion on when a new coder should learn to use behaviour vs protocol

You came across completely fine. :) I am just suggesting to move the discussion to somewhere more appropriate given it now has become a Dict-proposal. All good.

Thanks for taking your time to improve Elixir!

Reply all
Reply to author
Forward
0 new messages