I can see that this issue is convoluted.  There appears to be competing 
requirements, and getting things to start humming is non trivial.

Instead of dealing with "what if-s"... I want to start with more concrete 
"what does"...

*Transgressions.sin*
First, I don't fully understand Jeff's talk about "Transgressions.sin".  I 
disagree that "you can't get both behaviors" with map(sin, [1.0, "sloth", 
2pi, "gluttony"]).

I tried the following code in Julia, and everything works fine:
module Transgressions
    Base.sin(x::String) = "Sin in progress: $x"
end

using Transgressions #Doesn't really do anything in this example...
map(sin, [1.0, "sloth", 2pi, "gluttony"])

This tells me that when one uses map on an Array{Any}, Julia dynamically 
checks the object type, and applies multi-dispatch to execute the expected 
code.

I admit that one could argue this is not how "object oriented design" 
usually deals with this... but that's duck typing for you!

Ok... so what is the *real* problem (as I see it)?  Well, the problem is 
that Julia essentially decides that Base "owns" sin... simply because it 
was defined first.

The workaround here was to "extend" Base.sin from module "Transgressions".  
This works reasonably well when one *knows* that Base defines the sin 
"family of methods"... but not very good when one wants to appropriate a 
new verb (enable, trigger, paint, draw, ...).

Why should any one module "own" such a verb (family of methods)?  This 
makes little sense to me.

*As for Michael Turok's idea of the "SuperSecretBase"*
As some people have pointed out, SuperSecretBase is a relatively elegant 
way to define a common interface for multiple implementations (Ex: 
A/BConnectionManager).  However, this is not really appropriate in the case 
when modules want to use the same verb for two completely different domains 
(ex: draw(x::Canvas, ...) vs draw(x::SixShooter, ...)).

And, as others have also pointed out: the SuperSecretBase solution is not 
even that great for modules that *do* want to implement a common 
interface.  If company A needs to convince standards committee X to settle 
on an interface of accepted verbs... that will surely impede on product 
deployment.  And even then... Why should standards committee X "own" that 
verb in the first place???  Why not standards committee Y?

*Regarding the comment about not using "using"*
Well, that just seems silly to me... by not using "using"... you completely 
under-utilize the multi-dispatch engine & its ability to author crisp, 
succinct code.

==>And I would like to point out: The reason that multi-dispatch works so 
well at the moment is because (almost) everyting in Julia is "owned" by 
Base... so there are no problems extending methods >>>>In base Julia<<<<

*Some improvements on Transgressions.sin*
FYI: I don't really like my previous example of Transgressions.sin.  The 
reason: The implementation does not make sufficient use of what I would 
call "hard types" (user-defined types).  Instead, it uses "soft types" 
(int/char/float/string).

Hard types are very explicit, and they take advantage of multiple 
dispatch.  On the other hand, a method that takes *only* soft types is more 
likely to collide with others & fail to be resolved by multiple dispatch.

I feel the following example is a *much* better implementation to resolve 
the sin paradox:
module Religion
    #Name "Transgressions" has a high-likelyhood of name collisions - don't 
"export":
    type Transgressions; name::String; end

    #Personally, I find this "Transgressions" example shows that base 
should *not* "own" sin.
    #Multi-dispatch *should* be able to deal with resolving ambiguities...
    #In any case, this is my workaround for the moment:
    Base.sin(x::Transgressions) = "Sin in progress: $x"

    #Let's hope no other module wants to "own" method "absolve"...
    absolve(x::Transgressions) = "Sin absolved: $x"

    export absolve #Logically should have sin here too... but does not work 
with Julia model.
end

using Religion
Xgress = Religion.Transgressions #Shorthand... "export"-ing Transgressions 
susceptible to collisions.

map(sin, [1.0, Xgress("sloth"), 2pi, Xgress("gluttony")])

Initially, creating a type "Transgressions" seems to be overdoing things a 
bit.  However, I have not noticed a performance hit.  I also find it has 
very little impact on readability.  In fact I find it *helps* with 
readability in most cases.

Best of all: Despite requiring a little more infrastructure in the module 
definition itself, there is negligible overhead in the code that *uses* 
module Religion.

Reply via email to