Yep, that makes sense, thanks for showing the example. I already have another thread going on sorting out a "fetch" macro to introduce a local copy of the names in a type.
Out of interest, what is the "local" keyword for? http://julia.readthedocs.org/en/latest/manual/variables-and-scoping/ On Thursday, June 12, 2014 1:39:19 PM UTC+8, Keno Fischer wrote: > > There is no plans for namespace support other than what's already in with > modules. > > I'll try to explain. Say you have a mutable > type foo > a::Int > b::Int > end > > Then to modify it in a function you have to explicitly say > function bar(f::foo) > f.a = 2 > f.b = 3 > end > > etc., for it to modify my argument foo. I think it's way too easy to > refactor a function say > > function bar(f::foo) > ... lots of stuff ... > a = 2*f.a > ... lots of stuff ... > f.b*10*a > end > > into > > function bar(f::foo) > using f > ... lots of stuff ... > a = 2*f.a > ... lots of stuff ... > b*10*a > end > > because you want to immediately access b, but forgot that foo also has an > a field. In general in julia an assignment like > > var = value > > will almost never have effects outside it's current scope (var[idx] = and > var.field = are different). The only exception to this is if you write > > function test() > global var > var = value > end > > but as you can see that annotation is very explicit and limited. I would > be similarly opposed to a language feature that causes all variables in a > function to implicitly be global. > > As I said this isn't a concern in the immutable case because the > subsequent assignment would always override the original value and simple > assignments will not have effects outside the current scope. This can be > implemented with macros though. > > Hope that clarifies it, > Keno > > > On Thu, Jun 12, 2014 at 1:30 AM, Andrew Simper <[email protected] > <javascript:>> wrote: > >> Are namespaces going to be supported in julia? It would be the same >> mechanism as that, an order of preference to choose what a particular name >> is referring to, no more. So if julia is not going to support "using" on a >> namespace then I completely understand not wanting to support it on >> variables as I have suggested. >> >> I don't follow what you mean by "The mutable case has me worried. It >> introduces the possibility that an assingment (a simple one, not a setfield >> or getindex) actually has effects outside of the function which doesn't >> happen anywhere else in julia." >> >> Can you please provide an example to illustrate what you are worried >> about? >> >> >> On Thursday, June 12, 2014 1:21:14 PM UTC+8, Keno Fischer wrote: >> >>> In my opinion, looking at that example this is way to magical. Plus the >>> general consensus is that you should only add syntax if it is something >>> extremely special that requires compiler support. For the non-mutable case, >>> that's not the case here. The mutable case has me worried. It introduces >>> the possibility that an assingment (a simple one, not a setfield or >>> getindex) actually has effects outside of the function which doesn't happen >>> anywhere else in julia. >>> >>> >>> On Thu, Jun 12, 2014 at 1:07 AM, Andrew Simper <[email protected]> >>> wrote: >>> >>>> The problem with using a macro is that you will always have to make a >>>> local copy of the data, if it was a language feature then then a mutable >>>> type could be passed in as the argument and the same non-obfuscated code >>>> could be used to update the state in place, which may be preferable >>>> depending on the situation. >>>> >>>> Here is another example from the Julia.org webpage: >>>> >>>> immutable Pixel >>>> r::Uint8 >>>> g::Uint8 >>>> b::Uint8 >>>> end >>>> >>>> function rgb2gray!(img::Array{Pixel}) >>>> for i=1:length(img) >>>> p = img[i] >>>> v = uint8(0.30*p.r + 0.59*p.g + 0.11*p.b) >>>> img[i] = Pixel(v,v,v) >>>> end >>>> end >>>> >>>> function rgb2gray2!(img::Array{Pixel}) >>>> for i=1:length(img) >>>> using img[i] >>>> v = uint8(0.30*r + 0.59*g + 0.11*b) >>>> img[i] = Pixel(v,v,v) >>>> end >>>> end >>>> >>>> >>>> >>>> On Thursday, June 12, 2014 12:30:05 PM UTC+8, Keno Fischer wrote: >>>> >>>>> I don't think it warrants syntax, but might be nice in a macro. I've >>>>> had cases where I just put my entire simulation state in a single object, >>>>> so I don't need to give 100s of parameters to every object. In that case >>>>> (where the object is more of a container than an abstraction), it might >>>>> be >>>>> nice to use. >>>>> >>>>> >>>>> On Thu, Jun 12, 2014 at 12:13 AM, Andrew Simper <[email protected]> >>>>> wrote: >>>>> >>>>>> So just to post again to make things clearer, right now algorithms >>>>>> tend to look pretty ugly and obfuscated since you have to prefix >>>>>> function >>>>>> arguments with the argument names using dot notation: >>>>>> >>>>>> function tick (state::SvfSinOsc, coef::SvfSinOscCoef) >>>>>> local v1::Float64 = coef.g0*state.ic1eq - coef.g1*state.ic2eq >>>>>> local v2::Float64 = coef.g1*state.ic1eq + coef.g0*state.ic2eq >>>>>> SvfSinOsc (2*v1 - state.ic1eq, 2*v2 - state.ic2eq) >>>>>> end >>>>>> >>>>>> >>>>>> This is a lot more readable to me, and it would be super useful to >>>>>> have a "using" type operation similar to namespace but it could run on >>>>>> variables instead, so that although writing the following is equivalent >>>>>> to >>>>>> what is above, it is much easier to see what is going on: >>>>>> >>>>>> function tick (state::SvfSinOsc, coef::SvfSinOscCoef) >>>>>> using state, coef >>>>>> local v1::Float64 = g0*ic1eq - g1*ic2eq >>>>>> local v2::Float64 = g1*ic1eq + g0*ic2eq >>>>>> SvfSinOsc (2*v1 - ic1eq, 2*v2 - ic2eq) >>>>>> end >>>>>> >>>>>> What are peoples opinions on this? Would anyone else find it useful? >>>>>> >>>>>> >>>>>> >>>>>> On Friday, June 6, 2014 3:17:31 PM UTC+8, Andrew Simper wrote: >>>>>>> >>>>>>> In implementations where you want named data, I've noticed that the >>>>>>> algorithm gets obfuscated by lots of variable names with dots after >>>>>>> them. >>>>>>> For example, here is a basic analog model of a state variable filter >>>>>>> used >>>>>>> as a sine wave generator: >>>>>>> >>>>>>> immutable SvfSinOscCoef >>>>>>> g0::Float64 >>>>>>> g1::Float64 >>>>>>> end >>>>>>> immutable SvfSinOsc >>>>>>> ic1eq::Float64 >>>>>>> ic2eq::Float64 >>>>>>> end >>>>>>> function SvfSinOscCoef_Init (;freq=1.0, sr=44100.0) >>>>>>> local g::Float64 = tan (2pi*freq/sr) >>>>>>> local g0 = 1.0/(1.0+g^2) >>>>>>> SvfSinOscCoef (g0,g*g0) >>>>>>> end >>>>>>> function SvfSinOsc_Init (startphase::Float64) >>>>>>> SvfSinOsc (cos(startphase), sin(startphase)) >>>>>>> end >>>>>>> >>>>>>> But the tick function looks a bit messy: >>>>>>> >>>>>>> function tick (state::SvfSinOsc, coef::SvfSinOscCoef) >>>>>>> local v1::Float64 = coef.g0*state.ic1eq - coef.g1*state.ic2eq >>>>>>> local v2::Float64 = coef.g1*state.ic1eq + coef.g0*state.ic2eq >>>>>>> SvfSinOsc (2*v1 - state.ic1eq, 2*v2 - state.ic2eq) >>>>>>> end >>>>>>> >>>>>>> >>>>>>> It would be really cool if there was a way to shorthand the syntax >>>>>>> of this to something like the following, which is a lot more readable: >>>>>>> >>>>>>> function tick (state::SvfSinOsc, coef::SvfSinOscCoef) >>>>>>> using s, c >>>>>>> local v1::Float64 = g0*ic1eq - g1*ic2eq >>>>>>> local v2::Float64 = g1*ic1eq + g0*ic2eq >>>>>>> SvfSinOsc (2*v1 - ic1eq, 2*v2 - ic2eq) >>>>>>> end >>>>>>> >>>>>>> >>>>>>> Lots of algorithms have arguments with the same type, but even then >>>>>>> you could still specify using just the most used argument, but if it >>>>>>> doesn't help make things more clear or isn't useful then people don't >>>>>>> have >>>>>>> to use it at all. >>>>>>> >>>>>>> >>>>>>> >>>>>>> Another pattern that would be nice to handle cleanly is: fetch state >>>>>>> to local, compute on local, store local to state. I have written code >>>>>>> that >>>>>>> generates code to handle this since it is such a pain to keep >>>>>>> everything in >>>>>>> sync, but if there was some way to automate this at the language level >>>>>>> then >>>>>>> it would really rock, so here is an example of the longhand way, which >>>>>>> isn't too bad for this example, but just imagine if there are 20 or so >>>>>>> variables, and you are writing multiple tick functions: >>>>>>> >>>>>>> type SvfSinOsc >>>>>>> ic1eq::Float64 >>>>>>> ic2eq::Float64 >>>>>>> end >>>>>>> >>>>>>> function tick (state::SvfSinOsc, coef::SvfSinOscCoef) >>>>>>> local ic1eq::Float64 = state.ic1eq >>>>>>> local ic2eq::Float64 = state.ic2eq >>>>>>> for i = 1:100 >>>>>>> # compute algorithm using local copies of state.ic1eq and >>>>>>> state.ic2eq >>>>>>> end >>>>>>> state.ic1eq = ic1eq >>>>>>> state.ic2eq = ic2eq >>>>>>> return state >>>>>>> end >>>>>>> >>>>>>> >>>>>>> I have a feeling that macros may be able to help out here to result >>>>>>> in something like: >>>>>>> >>>>>>> function tick (state::SvfSinOsc, coef::SvfSinOscCoef) >>>>>>> @fetch state >>>>>>> for i = 1:100 >>>>>>> # compute iterative algorithm using local copies of >>>>>>> state.ic1eq and state.ic2eq >>>>>>> end >>>>>>> @store state >>>>>>> return state >>>>>>> end >>>>>>> >>>>>>> But I'm not sure how to code such a beast, I tried something like: >>>>>>> >>>>>>> macro fetch(obj::SvfSinOsc) >>>>>>> return quote >>>>>>> local ic1eq = obj.ic1eq >>>>>>> local ic2eq = obj.ic2eq >>>>>>> end >>>>>>> end >>>>>>> >>>>>>> macro store(obj::SvfSinOsc) >>>>>>> return quote >>>>>>> obj.ic1eq = ic1eq >>>>>>> obj.ic2eq = ic2eq >>>>>>> end >>>>>>> end >>>>>>> >>>>>>> dump(osc) >>>>>>> macroexpand (:(@fetch osc)) >>>>>>> macroexpand (:(@store osc)) >>>>>>> >>>>>>> SvfSinOsc >>>>>>> ic1eq: Float64 1.0 >>>>>>> ic2eq: Float64 0.0 >>>>>>> >>>>>>> >>>>>>> Out[28]: :($(Expr(:error, TypeError(:anonymous,"typeasse >>>>>>> rt",SvfSinOsc,:osc)))) >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>> >>> >
