Do note, in my example the lines like:

def compare(%Bike{gears: gears0}, %Bike{gears: gears1}), do: compare(gears0, 
gears1)

The `compare(gears0, gears1)` part is writer-defined, it could call into a 
module function, it could do an inline compare like the above is doing, 
whatever is appropriate for the type.



On Monday, August 29, 2016 at 3:04:17 PM UTC-6, OvermindDL1 wrote:
>
> On Monday, August 29, 2016 at 2:26:41 PM UTC-6, Wiebe-Marten Wijnja wrote:
> The idea is to be able to create application-specific comparisons between 
> data types, *where these comparisons make sense*.
>
> Hmm, being able to compare disjoint types seems potentially painful and 
> most likely incurring a significant overhead compared to just doing it 
> manually...  I'm guessing that is where the module explosion talked of 
> before came in to play.  It sounds like needing to create a multi-method 
> dispatcher in Elixir, and if so the best you could get (without knowing all 
> types absolutely at compile-time) would be log(N) runtime, which is not too 
> bad...
>
> You could potentially sneak in some tricks though.  If you use something 
> like protocols (though something new, not protocol) to generate a call tree 
> in a single module, a single entrance function that matches based on both 
> of the types (properly ordered so the beam can efficiently match well) 
> would get it down to log(n).  Hmm, although if you have a *lot* of 
> potential matches (and I mean a **LOT**) then you could dispatch into a map 
> and that 'might' be faster (though honestly I would not bet on it).  This 
> would require a post-compile step like protocols do though (is there a 
> pattern to do those kind of things with elixir or are protocols just 
> 'special'?).  For normal macro's the best you could really get is to 
> manually specify everything in a single file in your base project, just 
> import the other modules that define matchers, and have a macro build up 
> the same call tree.  Easy enough to do but does require the end-user to 
> import all other possible modules compare implementations into it so the 
> macro can build the call tree, which can be easy to forget something, but 
> good enough for an initial test implementation.
>
> With that you would only have 1 module necessary (with an additional 1 for 
> each you import, but those could just be function calls onto some base 
> module for each type so that is effectively free).  But the macro would 
> just generate something like:
> ```elixir
>
> # Example structsdefmodule Bike do
>   defstruct gears: 5end
> defmodule Car do
>   defstruct top_speed: 80end
> defmodule Truck do
>   defstruct wheels: 4
>   def compare(%{wheels: wheels0}, %{wheels: wheels1}), do: 
> Comparable.compareend
> # An example of what a macro could generate given some information that 
> describes things:defmodule Comparable do
>   def compare(t, t), do: :eq  # Could generalize this call to something like: 
>  # def compare(%{__struct__: type}=t0, %{__struct__: type}=t1), do: 
> type.compare(t0, t1)  # However that catches structs that do not support a 
> compare and has a speed overhead due to dynamic dispatch, so I would not 
> recommend it
>   def compare(%Bike{gears: gears0}, %Bike{gears: gears1}), do: 
> compare(gears0, gears1)
>   def compare(%Bike{}, %Car{}), do: :lt
>   def compare(%Bike{}, %Truck{}), do: :lt
>   def compare(%Car{top_speed: top_speed0}, %Car{top_speed: top_speed1}), do: 
> compare(top_speed0, top_speed1)
>   def compare(%Car{}, %Bike{}), do: :gt
>   def compare(%Car{}, %Truck{}), do: :lt
>   def compare(%Truck{wheels: wheels0}, %Truck{wheels: wheels1}), do: 
> compare(wheels0, wheels1)
>   def compare(%Truck{}, %Bike{}), do: :gt
>   def compare(%Truck{}, %Car{}), do: :gt
>   def compare(%{__struct__: _t0}, %{__struct__: _t1}, do: raise 
> MatchError(blah)
>   def compare(t0, t1), do: if(t0<t1, then: :lt, else: if(t0>t1, do: :gt, 
> else: if(t0 == t1, do: :eq, else: raise MatchError(blah))))end
>
> ```
> That should be quite easily optimizable by the beam and be quite 
> efficient, even with large match sets (log(n) specifically).
>
> On Monday, August 29, 2016 at 2:58:15 PM UTC-6, José Valim wrote:
>>
>> Given the examples below, maybe it would be better to provide protocols 
>> for each of those cases. The protocol would convert those data types to an 
>> intermediate representation that would be easy to compare on.
>
>  
> This could indeed be faster, however you'd have to get everything to agree 
> on a single representation (a special tuple format perhaps? but then how 
> would that rank with other tuples?).
>
>>

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/d1cc865e-11d6-4d56-bead-63a0f3dea3c4%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to