On Saturday, April 25, 2015 at 4:56:58 AM UTC+10, Stefan Karpinski wrote: > > 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. >
I would have thought stopping intentional behaviour is non-Julian, but accidental errors should indeed be limited. Perhaps adding methods to other modules functions needs to explicit. > > On Wed, Apr 22, 2015 at 6:19 PM, Jeff Bezanson <[email protected] > <javascript:>> 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] >> <javascript:>> 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> >> > >
