For anyone who isn't following changes to Julia master closely, Jeff closed
#4345 <https://github.com/JuliaLang/julia/issues/4345> yesterday, which
addresses one major concern of "programming in the large".

I think the other concern about preventing people from intentionally or
accidentally monkey-patching is very legitimate as well, but it's way less
clear what to do about it. I've contemplated the idea of not allowing a
module to add methods to a generic function unless it "owns" the function
or one of the argument types, but that feels like such a fussy rule, I
don't think it's the right solution. But I haven't come up with anything
better either.

On Wed, Apr 22, 2015 at 6:19 PM, Jeff Bezanson <[email protected]>
wrote:

> I think it's reasonable to adopt a convention in some code of not using
> `using`.
>
> Another way to look at this is that a library author could affect name
> visibility in somebody else's code by adjusting the signature of a
> method. That doesn't seem like a desirable interaction to me. Often
> somebody might initially define foo(::Image), and then later realize
> it's actually applicable to any array, and change it to
> foo(::AbstractArray). Doing that shouldn't cause any major fuss.
>
> On Wed, Apr 22, 2015 at 5:58 PM, Michael Francis <[email protected]>
> wrote:
> > You are correct it is restrictive, though I will take some convincing
> that
> > this is a bad thing, as systems get larger in Julia it is going to be
> > increasingly important to manage code reuse and prevent accidental
> masking
> > of types. Multiple dispatch is a wonderful tool for supporting these
> goals.
> > Unfortunately allowing people the ability to export get(<string>) et al
> to
> > the users scope seems like a bad idea. This is already happening from
> > modules today. Perhaps the middle ground is to force an explicit import,
> so
> > using only imports functions which have types defined in the module.  The
> > person defining the module exports all the functions they want but only
> > those that are 'safe' e.g. follow my original rule are implicitly
> imported.
> > Hence you would have something like the following code. This is not far
> > different from the importall today, except that the exports are
> > automatically restricted.
> >
> > using MyMath         # Imports only those functions which include types
> > defined in MyMath
> > import MyMath.*      # Imports all other  functions  defined in MyMath
> > import MyMath.afunc  # Imports  one  function
> > import MyOther.afunc # Fails collides with MyMath.afunc
> >
> >
> >
> >
> >
> >
> > On Wednesday, April 22, 2015 at 4:40:03 PM UTC-4, Jeff Bezanson wrote:
> >>
> >> That rule seems extremely restrictive to me. It would be very common,
> >> for example, to create a library of functions that operate on standard
> >> data types like numbers and arrays. I don't see that we can exclude
> >> that kind of use.
> >>
> >> Also, printing a warning is not the key part of #4345. The important
> >> part is that you'd have to qualify names in that case, which is the
> >> same thing that would happen if `export`ing the names were disallowed.
> >>
> >>
> >> On Wed, Apr 22, 2015 at 8:47 AM, Michael Francis <[email protected]>
> >> wrote:
> >> > I read through the issues / threads ( and some others )
> >> >
> >> > https://github.com/JuliaLang/julia/issues/2327
> >> > https://github.com/JuliaLang/julia/issues/4345
> >> >
> >> > I'm not sure that the either the SuperSecretBase or the warning are
> the
> >> > correct approach. I'd like to propose a counter which is a very simple
> >> > rule.
> >> >
> >> > "You can only export functions from a module where they reference at
> >> > least
> >> > one type defined in the module."
> >> >
> >> > There may have to be a slight tweak for Base, though it is not hard to
> >> > argue
> >> > that the primitive types are defined in Base.
> >> >
> >> > so
> >> >
> >> > module Module1
> >> > type Bar end
> >> > my( b::Bar ) = 1
> >> >
> >> > export my       # fine exports to the global space
> >> > end
> >> >
> >> > module Module2
> >> > type Foo end
> >> > my() = 1
> >> >
> >> > export my       # ERROR exporting function which does not reference
> >> > local
> >> > type
> >> > end
> >> >
> >> > module Module3
> >> > type Wow end
> >> > my( w::Wow ) = 1
> >> > my() = 1
> >> > end
> >> > export my       # Is an ERROR I can not export a function which does
> not
> >> > reference a local type
> >> > end
> >> >
> >> > So in the example provided my Mike above, multiple dispatch would do
> the
> >> > right thing. If I also want to define a function for value in my
> module
> >> > it
> >> > would work consistently against the types I define. We don't have to
> >> > perform
> >> > recursive exports and import usage should be reduced.
> >> >
> >> > If you want to define an empty function you can do so with a default
> arg
> >> > module Module4
> >> > type Zee end
> >> > my( ::Type{Zee} = Zee ) = 1
> >> > export my       # Works, but I can select against it using multiple
> >> > dispatch
> >> > by providing the last arg
> >> > end
> >> >
> >> >
> >> > I can't convince myself that exporting Types in general (nor macros)
> is
> >> > a
> >> > good idea.
> >> >
> >> > A tweak may be to add C# like module alias syntax, which is just
> >> > syntactic
> >> > sugar over what we have ( except that we would likely want the
> >> > definition of
> >> > MY to be const in the scope.
> >> >
> >> > MY = using Foo.Bar.ReallyLongModuleName
> >> > t = MY.Type()
> >> > my( t )
> >> >
> >> >
> >> > Thoughts ?
> >> >
> >> >
> >> > I'm sure there is something I have missed, but this simple rule would
> >> > seem
> >> > to encourage multiple dispatch and support the development of modules.
> >> >
> >> > On Tuesday, April 21, 2015 at 1:07:40 PM UTC-4, Jeff Bezanson wrote:
> >> >>
> >> >> We're planning to do something about this: #4345. When `using` two
> >> >> modules with conflicting names, we should do something other than
> pick
> >> >> one depending on order. Most likely we will print a warning, and
> >> >> require uses of the name to be qualified.
> >> >>
> >> >> If the two modules really do want to define different methods for the
> >> >> same function, then either one has to import the other, or you have
> to
> >> >> use your SuperSecretBase approach.
> >> >>
> >> >> On Tue, Apr 21, 2015 at 9:37 AM, Michael Turok <[email protected]>
> >> >> wrote:
> >> >> > Note that this can be made to work by tearing a page from Base:  we
> >> >> > can
> >> >> > a
> >> >> > module (SuperSecretBase), that defines a stub value() function. We
> >> >> > then
> >> >> > use
> >> >> > importall SuperSecretBase in each of Foo and Bar.    But this means
> >> >> > that
> >> >> > any
> >> >> > module we create would need to declare its functions into
> >> >> > SuperSecretBase.
> >> >> >
> >> >> > julia> workspace() ; include("mike.jl")
> >> >> >
> >> >> > julia> using Foo
> >> >> >
> >> >> > julia> using Bar
> >> >> >
> >> >> > julia> value(Bar.BarType())
> >> >> > "Bar::value"
> >> >> >
> >> >> > julia> value(Foo.FooType())
> >> >> > "Foo::value"
> >> >> >
> >> >> > julia>
> >> >> >
> >> >> > Modified code follows:
> >> >> >
> >> >> > module SuperSecretBase
> >> >> > value() = nothing
> >> >> > export value
> >> >> > end
> >> >> >
> >> >> > # ------------------------------
> >> >> >
> >> >> > module Foo
> >> >> >
> >> >> > importall SuperSecretBase
> >> >> >
> >> >> > importall Base
> >> >> > type FooType end
> >> >> >
> >> >> > value(x::FooType) = "Foo::value"
> >> >> > get(x::FooType) = "Foo::get"
> >> >> >
> >> >> > export value
> >> >> >
> >> >> > end
> >> >> >
> >> >> > # ------------------------------
> >> >> >
> >> >> > module Bar
> >> >> >
> >> >> > importall SuperSecretBase
> >> >> >
> >> >> > importall Base
> >> >> >
> >> >> > type BarType end
> >> >> >
> >> >> > value(x::BarType) = "Bar::value"
> >> >> > get(x::BarType) = "Bar::get"
> >> >> >
> >> >> > export value
> >> >> >
> >> >> > end
> >> >> >
> >> >> >
> >> >> >
> >> >> >
> >> >> > On Tuesday, April 21, 2015 at 9:26:01 AM UTC-4, Michael Turok
> wrote:
> >> >> >>
> >> >> >> Hi,
> >> >> >>
> >> >> >> What is the idiomatic way to create a function value() in
> different
> >> >> >> modules, dispatched on different arguments, without getting the
> >> >> >> warning/error about conflicting with an existing identifier?
> >> >> >>
> >> >> >> It seems like there is an order dependency with the example below.
> >> >> >> Seems
> >> >> >> like the 2nd module defines value(), unless you had already used
> >> >> >> value()
> >> >> >> prior to importing the 2nd module.
> >> >> >>
> >> >> >> Note that if I do the same with get() a function defined in Base,
> I
> >> >> >> don't
> >> >> >> get an error.
> >> >> >>
> >> >> >> Code and output from julia REPL below.
> >> >> >>
> >> >> >> Any help appreciated,
> >> >> >> Michael
> >> >> >>
> >> >> >> # this is mike.jl
> >> >> >>
> >> >> >> # ------------------------------
> >> >> >> module Foo
> >> >> >> # ------------------------------
> >> >> >> importall Base
> >> >> >> type FooType end
> >> >> >>
> >> >> >> value(x::FooType) = "Foo::value"
> >> >> >> get(x::FooType) = "Foo::get"
> >> >> >>
> >> >> >> export value
> >> >> >>
> >> >> >> end
> >> >> >>
> >> >> >> # ------------------------------
> >> >> >> module Bar
> >> >> >> # ------------------------------
> >> >> >> importall Base
> >> >> >>
> >> >> >> type BarType end
> >> >> >>
> >> >> >> value(x::BarType) = "Bar::value"
> >> >> >> get(x::BarType) = "Bar::get"
> >> >> >>
> >> >> >> export value
> >> >> >>
> >> >> >> end
> >> >> >>
> >> >> >> Using this in the REPL:
> >> >> >> julia> workspace() ; include("mike.jl")
> >> >> >>
> >> >> >> julia> using Foo
> >> >> >>
> >> >> >> julia> value(Foo.FooType())
> >> >> >> "Foo::value"
> >> >> >>
> >> >> >> julia> using Bar
> >> >> >> Warning: using Bar.value in module Main conflicts with an existing
> >> >> >> identifier.
> >> >> >>
> >> >> >> julia> value(Bar.BarType())
> >> >> >> ERROR: `value` has no method matching value(::BarType)
> >> >> >>
> >> >> >> # -----------------------------------------------------
> >> >> >>
> >> >> >> julia> workspace() ; include("mike.jl")
> >> >> >>
> >> >> >> julia> using Foo
> >> >> >>
> >> >> >> julia> using Bar
> >> >> >>
> >> >> >> julia> value(Foo.FooType())
> >> >> >> ERROR: `value` has no method matching value(::FooType)
> >> >> >>
> >> >> >> julia> value(Bar.BarType())
> >> >> >> "Bar::value"
> >> >> >>
> >> >> >> # -----------------------------------------------------
> >> >> >>
> >> >> >> julia> workspace() ; include("mike.jl")
> >> >> >>
> >> >> >> julia> using Bar
> >> >> >>
> >> >> >> julia> using Foo
> >> >> >>
> >> >> >> julia> value(Foo.FooType())
> >> >> >> "Foo::value"
> >> >> >>
> >> >> >> julia> value(Bar.BarType())
> >> >> >> ERROR: `value` has no method matching value(::BarType)
> >> >> >>
> >> >> >> julia>
>

Reply via email to