Hi
Understood.... But I thought with a Protocol I *can* have all of the
above? I don't see that any of the above isn't true both for a
Behaviour or a Protocol?
- Default implementations (non optimal) are provided through the
Protocol fallback (just as they are at present through the behaviour
__USING__)
- If I need an optimised "get_and_update" for my specific datatype
then I just define that protocol instead of relying on the default
implementation (just as at present where there are overrides in
HashDict/Map)
What am I missing? I am anticipating that the code would remain
identical in HashDict/Map, only the method of dispatching to the
functions is what I'm proposing?
But why doesn't it make sense to pull all of Dict into a protocol?
Seems like a fine Protocol to me? It already *is* an interface
definition in that its a behaviour, all I'm saying is that its a
fine interface and perhaps we should make use of it more widely
elsewhere?
Its no problem for me to pull KV/Dict into my own protocol, so will
Bob, and so will Dave and Jane and so on and we will all repeat each
other. My observation is that this looks like a re-usable
"paradigm", (ie show me a modern language which doesn't have a built
in Dict/Hash type?), so why not push it out as a core concept for
people to re-use in their projects?
Why is Enum a more obvious Protocol than Dict?
Can you explain what difference you see in Dict vs Key-Value? To me
they are synonymous types?
Conversely, the reason I would argue for a clear interface is
*BECAUSE* if you aren't careful, one tends to add functions based on
some knowledge that "it's implemented as a hash" and forget that you
are implementing "a Dict". ie you get drawn into knowledge of your
implementation. If you aren't careful you will implement things
that work well for HashDict and would be problematic for Map say.
Finally, this is a philosophical question because I'm still trying
to get my head around functional programming, but:
- Isn't the whole point that we look at FP as about the *function*
on the data?
- Ie we think in terms of what we want the function to *do*, and
less about what the data is?
This is why I am coming at the problem in terms of "I want to put/3
some value into this datatype". Of course I also am conscious of
efficiency, (but for the vast number of situations efficiency is not
a problem.)
OK, I'm happy with that. Can we have a Dictionary protocol please?
I'm not really getting why you think Dict isn't a Key-Value? The
words feel the same to me? I look at the docs page for Dict and it
basically shows me all the functions I might expect to implement for
all kinds of things from a cache store to an advanced priority
queue? For example, if I wanted a generic config parser, I would
suggest that Dict is a great starting point for an interface?
I would have thought Erlang was already a great example of how one
can bend a few careful interfaces and re-use them in wonderful
ways? We have gen_server which can become almost anything. I don't
quite see why Dict isn't a candidate for careful re-use in all kinds
of wonderful ways?
Sure... But I don't see a behaviour is any less easy to change than
a protocol? Both are about getting it out there and kicking it
around and seeing who can offer some insight?
I'm suggesting to leave the actual functions exactly as it is. The
interface functions looks fine to me whether its a behaviour or a
protocol?
Don't see that this makes a difference? That's a problem for the
implementation? In all cases though the interface will be the same!
Err? Aren't you arguing FOR protocols here?
If you used a Protocol then you would call the generic interface in
all cases and automatically get upgraded to the specific
implementation if one was provided? This is surely BETTER than
having to figure out whether you use the generic or specific
implementation in your code!
Sorry, I'm not getting it? You solve this by just defining a
specific count/1 protocol function for Map/HashDict and now count
works optimally on all our Dictionary types? Isn't this what you are
supposed to do anyway? (define a count function if you can do better
than the default reduce implementation)
This is already how it seems to work, eg Enum.count for HashDict
simply calls HashDict.size:
https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/hash_dict.ex#L233
Maps appears to call :erlang.map_size (although because it's not a
protocol this is tricky to discover as it needs to be implemented in
enum.ex...)
So right now I don't see that size gives a different answer to count
for the current Dictionary types? Can you explain when and where it
would? If it doesn't then why do we need both implementations if
they give identical answers?
Yeah, but count/1 will have constant time implementations for
situations where it's possible?
I'm not sure I understand your point here? Some future actual
Dictionary might really not have a constant time size function
available? eg I could write some tree implementation which doesn't
bother to record the number of nodes, I would still have to
implement the size function (because it says so in the behaviour
spec), but the result wouldn't be constant time just because of the
function name?
I don't see any special reason all Dictionaries will implement
constant time size functions (although I concede they would be
foolish not to...). Likewise I would expect many other non
dictionary structures to be able to implement Enum.count in constant
time
You can ignore the rest of my email, but I really think you
should reconsider if we need Dictionary.size, given that
Enum.count is implemented optimally for all Dictionary types?
Likewise almost EVERYONE needs an equal?/2 function for their
datatype don't they?! Why don't we bang that in as a standard
protocol right away??!
Performance is a superb reason not to do this. Is this the real
answer? In which case I learn from this not to use Protocols in my
performance critical code? (Remember I started out by asking a
question about when I should use Protocols and when I should use
Behaviour with a handrolled polymorphism a-la Dict)
Hmm, most of the world would argue that abstracting things generally
helps clean them up? I could implement some tree direct in my
datastructure, but it's usually a win to say abstract it out into a
dictionary a-like type and simplify the interfaces.
I would strongly argue that the Hash, (and Array) interface is an
*extremely* common pattern to implement? For example, its
practically mandatory in Perl to offer a tied hash interface to any
interesting module. Wierd random example to illustrate: the link
below shows how you can search Google through a hash type datatype
(erk!):
http://search.cpan.org/~darren/Tie-Google-0.03/Google.pm
I won't hold up Perl as an example of why Elixir should do something
(!), but to say that the Hash/Dict pattern is universal and
extremely widely used seems like an understatement?
Cheers
Ed W