But you had to be explicit, redefining `A._f()`, as I read the Julia "consenting adults" ethos, if you are open and explicit about it you can play with anybody's private parts, but you are responsible for the results. Such monkey patching is occasionally useful, but it shouldn't be able to happen implicitly and silently which could be the case if Julia had automatic merging of functions.
On Sunday, May 3, 2015 at 1:54:18 AM UTC+10, Tom Breloff wrote: > > After reading this response, I realized that maybe I don't have a complete > grasp on how and when a module's method is overwritten/extended. I did a > simple test of what I thought might produce unexpected results, but in fact > worked exactly as I wanted it to! Bravo guys... every time I think there > might be a (very slight) hole in the design of the language, I am proven > wrong. :) > > Here's the test, which ensures that code from within that module will > always call a "clean" group of functions (even when a function is > exported!)... i.e. you can't change/replace the internal dispatch from > outside the module, which was my primary concern. Check out the numbers > highlighted in orange. If the internal call to _f(x) could be masked, they > should be -1... however that's not allowed so it (correctly) returns 999. > > In summary... please ignore all my comments above about private functions > since it already works the way I want, and thanks for teaching me a little > more about the language. > > > julia> module A > export f, _f > f(x) = _f(x) > _f(x) = 999 > end > > julia> using A > > julia> A.f(0), A.f(0.0), A._f(0), A._f(0.0) > (999,999,999,999) > > julia> f(0), f(0.0),_f(0), _f(0.0) > (999,999,999,999) > > julia> A._f(x::Float64) = -1 > _f (generic function with 2 methods) > > julia> A.f(0), A.f(0.0), A._f(0), A._f(0.0) > (999,*999*,999,-1) > > julia> f(0), f(0.0),_f(0), _f(0.0) > (999,999,999,-1) > > > > > On Friday, May 1, 2015 at 8:57:04 PM UTC-4, [email protected] wrote: >> >> >> >> On Friday, May 1, 2015 at 11:39:20 PM UTC+10, Tom Breloff wrote: >>> >>> I agree that auto-merging could cause hard-to-find bugs for the user. >>> This is less important than causing impossible-to-find bugs for a package >>> writer IMO. >>> >> >> I'm not sure I understand what impossible to find bug not merging >> functions causes. >> >> >> >>> >>> Here's a couple potential solutions for the user space issues: >>> >>> - "@verbose using SomeHugeModule" >>> - this could analyze the exported functions and check for name >>> clashes superficially (i.e. no concept of dispatch types) and print a >>> report of potentially dangerous method names >>> - new syntax: "using SomeHugeModule without fragileMethod1, >>> fragileMethod2" >>> - similar to "import A: x, y" but the reverse... allow everything >>> except those 2 methods to be imported >>> >>> Note that for a user that just wants to use a module without worrying >>> about safety, nothing changes. However for users building more complex >>> systems with many packages, they have a way to see potential clashes and >>> decide on their own how best to handle them. A "using ... without ..." >>> syntax would be super nice for some larger packages that mostly have unique >>> names exported, but may have a couple clashes. Then you can do "using" and >>> just add to the "without" list if any clashes become a problem. >>> >> >> The "without" syntax allows possible reductions in verbosity when >> excluding a few names from the import, and makes them visible, so it is >> useful, but it is only syntactic sugar, not any new solution. >> >> >>> >>> >>> And here's an idea for the package writer issue: >>> >>> @includes_private Module A >>> >>> f(x) = "not too important" >>> _f(x) = "important... must call this internally" # NOTE: the >>> underscore tells the @includes_private macro to "hide" this function from >>> the outside world >>> >>> function g() >>> bigobj = createHugeObject() >>> f(bigobj) >>> _f(bigobj) # we should be able to guarantee that this calls our >>> function above... even if someone defines A._f(x) elsewhere >>> end >>> >> >> Julia experts should correct me, but it is my understanding that within >> the module it will always call the definition local to the module (unless >> you import explicitly). To quote the manual "Within a module, you can >> control which names from other modules are visible (via importing)". >> >> >> >>> >>> >>> end >>> >>> using A >>> f(x) = "something orthogonal to A.f" >>> A._f(x) = "something else" # NOTE: this should either not be allowed >>> (hard) or at least not clash with A's _f(x)... maybe replacing _f with a >>> gensym within A?? >>> g() >>> >>> >>> I *think* these solutions are somewhat straightforward, and the only >>> thing that would change core julia is the "without" syntax. If changing >>> syntax is not worth it, maybe you could make a "using_without" macro? >>> >> >> I don't really understand what the @include_private macro does and what >> problem it solves. Just don't export _f(). >> >> >>> >>> @using_without SomeHugeModule fragileMethod1 fragileMethod2 >>> >>> And now that I think about it, you could combine these concepts into >>> another macro which would analyze for name clashes and add any potentially >>> dangerous method names to the without list: >>> >>> @safe_using SomeHugeModule >>> >>> >>> >>> Does this functionality exist already? Are these macros something the >>> community would want? I would be willing to work on it. >>> >>> >>> >>>
