[julia-users] Re: SI prefixes (M, k, m, u, n, ...)
Thanks Eric, I will see if the SIUnits group/Keno wants to absorb this functionality. If not, I suppose I will try registering it as a separate package. MA
[julia-users] SI prefixes (M, k, m, u, n, ...)
I often find it useful to display values using SI prefixes. For example, I find: 10.75n to be more readable than: 1.075e-8 ...So I created a module for this functionality: https://github.com/ma-laforge/NumericIO.jl *Question:* Should I be publishing this to METADATA? It seems a bit heavy to register an entire module for this simple functionality. Is there something else to do that would be more appropriate (a better place for this functionality)? *Comment:* This module makes use of Grisu, which I do not believe is a public feature of Julia... So I am not convinced it is technically "acceptable" to rely on it from an external module. MA
Re: [julia-users] Fortran-formatted files
Hi all, Maybe I am missing something myself... I too seem to find the Julia textfile reading facilities inadequate (or maybe I am using them wrong). As Jacob Quinn suggested, I tried using readdlm, but it only seems to work for text files with a regular structure. For example: #Comments at start #Comments at start ... #Comments at start #Regular table of data: data1, data2, data3, ... dataN data1, data2, data3, ... dataN data1, data2, data3, ... dataN ..But alot of existing file formats are *not* this regular ..So I have developped a temporary workaround (still waiting for someone to show me what I am doing wrong). *Solution* My solution is not as flexible as the scanf() tool, but it works well with the 90% of file formats that don't need that level of control. It is provided as part of the FileIO2 module: https://github.com/ma-laforge/FileIO2.jl The solution is based on a new type called "TextReader", constructed with: reader = TextReader(::IO, splitter= [' ', '\t']) (As with readdlm, you can add ',' to splitter for CSV files) The goal of the TextReader object is to take control of an ::IO stream, and provide higher-level read functionnality. To use it, you can open a text file using the "Base.open" method: reader = open(FileIO2.TextReader, "MYTEXTFILE.TXT") You can therfore read a regular file with the following pattern: while !eof(reader) data = read(reader, Int) println("Read: $(typeof(data))(`$data`)") end And you can read a more irregular data with the following: dataid = read(reader, AbstractString) dataval = read(reader, Int) dataid = read(reader, AbstractString) dataval = read(reader, Int) ... Note that the current method for `read(stream::IO, DataType)` considers the data stream to be binary... not text. However, by dispatching on a TextReader object, we can re-define the behaviour to be more appropriate for the task at hand. You can also let parse() auto-detect the type, for quick-and-dirty solutions: dataany = read(reader, Any) #Might return an Int, String, Float, ... Feel free to use it... but I suggest making a copy of the code. The FileIO2 interface is still in the experimental phase. It *will* change/break your code. *FileIO2 Comment* The solution in the FileIO2.jl module looks a bit complicated because it ties into a File{}-type-based-system. The different File{} types are used by Julia's dispatch system to call the appropriate open/read/write method (unique Julia signature). This is not possible when using simple Strings to pass the filename. FYI: Using the higher level API, one can use the simple, high-level call: reader = open(File(:text, "MYTEXTFILE.TXT")) This call uses Julia itrospection to detect text readers from any currently loaded module. Note that only the "FileIO2.TextReader" object performs this service at the moment... Regards, MA On Friday, March 7, 2014 at 4:20:30 PM UTC-5, Jacob Quinn wrote: > > Have you checked out `readdlm`? It's flexibility has grown over time and > serves most of my needs. > > http://docs.julialang.org/en/latest/stdlib/base/#Base.readdlm > > -Jacob >
[julia-users] Re: PyPlot does not work with Julia Version 0.4.0-rc1+5
Hi, First: I usually find PyPlot very robust... but am having trouble lately (sounds similar to your problems). *I try to keep my environment simple/clean:* Xubuntu 14.04 +Install Anaconda 2.4.1 (Newer version) +Install Julia 0.4 using : sudo add-apt-repository ppa:staticfloat/juliareleases sudo apt-get update sudo apt-get install julia Anyways, it seems like PyPlot is having issues working with certain combinations of numpy, matplotlib, and the graphic systems (looking at the compile error messages). *My Solution* After playing around a bit, I got PyPlot to work by using the following combination: conda install numpy=1.9.2 matplotlib=1.4 Though it seems like specifying an older cairo can help sometimes conda install numpy=1.9.2 cairo=1.12.2 matplotlib=1.4 NOTE: This solution seems very similar to the solution from Daniel Høegh: https://groups.google.com/d/msg/julia-users/kZQrK8-nmQ8/4NfSNGSRAwAJ ("PyPlot not working on 0.4.0") ...But his solution does not work for me. *Comments* I do not really understand the root cause of this issue, but I can say the following: 1. Installing numpy 1.9.3 or higher breaks my PyPlot. 2. Installing matplotlib 1.5 breaks my PyPlot. 3. "conda install" seems to work better if you sepcify all simultaneous requirements in a single statement. *Debug Tips* I can quickly determine if my Anaconda/PyPlot solution is working, by using the following steps: 1. Change the active group of python packages conda install ... 2. Rebuild pyplot & try loading it (which compiles as well): Pkg.build("PyPlot") using PyPlot #Re-compilation might/might not fail
Re: [julia-users] linspace-like range generators and keyword ordering
Thanks for clarifying that Josh. I thought my issues were because of a subtlety of Julia's type system that I did not understand.
Re: [julia-users] linspace-like range generators and keyword ordering
Thanks Matt, I kind of like the explicit nature of "Exactly". I will have to let the idea sink in a bit more.
Re: [julia-users] linspace-like range generators and keyword ordering
> > This looks like overengineering of what should be a simple problem. Why do > you want turn the keywords into arguments for dispatch? Dispatch is best > when you need different behavior for different types but here all your > input and output types are fixed. > I suppose there is some truth to that. I also look at Julia's dispatch system as an alternative to a case statement. But, unlike the case statement, you don't need to register the new function in the case statement. The function signature (that includes KD) takes care of that. You may have already known, but you can work with your keywords by doing > `kwdict = Dict(kwargs)`. That will let you do stuff like `haskey(kwdict, > :ts)` to decide which timespace algorithm to use. > Interesting... I never thought of that (not sure why). Thanks. > Some other points for future reference: > > - `immutable KD{Symbol} end` does not force the type parameter to be a > symbol. It does the same thing as the more typical 'T' (which could be > :tfund, Int, Array{Symbol,2}, or anything else). > Hmm... I have been having trouble with this one. I know I have succeeded with things like "abstract KD{T<:Number}" - but I don't seem to be able to do "abstract KD{T<:Symbol}", or "abstract KD{T::Symbol}". I don't understand why I cannot get this level of control. I would appreciate if you would have more insight on this part. > - timespace() and timespace(; kwargs...) are not separate methods. The > second one actually overrides any definition in the first one. > I should have known better than this. I did not notice that mistake. Thanks.
Re: [julia-users] linspace-like range generators and keyword ordering
OK, I'll give it a try (sorry about the length of the reply). *Idea behind "timespace":* Generates time vector (range) from sampling period & fundamental Automatically computes # of time steps, N. Why? Computation of N can easily be off-by-1 - if specified directly. So... with timespace, users can focus on the quantities that are truly of interest to them. Here is the current solution I have for timespace (called timespace2 here): #NOTE: first argument is targeted argument (will not get rounded - to 1st order) timespace2(primary::Symbol, v1, secondary::Symbol, v2; kwargs...) = timespace2(KD{primary}(), KD{secondary}(), v1, v2; kwargs...) timespace2{T1, T2}(::KD{T1}, ::KD{T2}, args...; kwargs...) = throw(ArgumentError("timespace2 does not support combination (:$T1, :$T2).")) Now, here is the version where the sampling period (timestep), ts is most important parameter: #Will throw error if "suggested" fundamental period does not land on the timestep: function timespace2(::KD{:ts}, ::KD{:tfund}, ts, tfund; tstart=0) const ABSTOL = .05 ns = tfund/ts ins = round(Int, ns) if abs(ns-ins) > ABSTOL throw("tfund must be approx. an integer multiple of ts.") end return tstart+(0:ts:((ins-1)*ts)) end ...and here is the version where the Fundamental period, tfund, is most important parameter: #Will throw error if fundamental period does not land on the "suggested" timestep: function timespace2(::KD{:tfund}, ::KD{:ts}, tfund, ts; tstart=0) const ABSTOL = .05 ns = tfund/ts ins = round(Int, ns) if abs(ns-ins) > ABSTOL throw("tfund must be approx. an integer multiple of ts.") end ts = tfund/ins #Re-compute most accurate possible version of timestep return tstart+(0:ts:((ins-1)*ts)) end Now here is how you generate the ranges: #The timestep is the important parameter... must not change: t1 = timespace2(:ts, 1e-9, :tfund, 20e-9, tstart = 2e-9) #The fundamental period is key... this version will do *minimal* rounding #(because I know of no range function that is directly specified using tfund, # and maximum(t2) <> tfund)... it is "ts" away from that point). t2 = timespace2(:tfund, 20e-9, :ts, 1e-9, tstart = 2e-9) Note: This syntax is not terrible, but when I wrote it up, I realized it was just a bit of syntactic sugar away from keyword arguments almost there... The nice thing with this type of solution is that I also don't need a different function name if I *do* want a version that takes number of timesteps (:n) as an argument (instead of either tfund or ts). Hope this helps clarify what I am trying to achieve. Thanks, MA
[julia-users] linspace-like range generators and keyword ordering
Hi users, I want to be able to generate ranges using a syntax similar to: t1=timespace(tstart = 2e-9, ts=1e-9, tfund=20e-9); t11=timespace(fs=1/1e-9, tfund=20e-9, tstart=3e-9); t2=timespace(tfund=20e-9, tstart=4e-9, ts=1e-9); *Why not just use different function names?*Simply put, I would rather not have to use long, ugly names like (timespace1, timespace2, timespace_tfund, timespace_ts, timespace_fs, ...) *What is unusual/difficult about this solution:* - linspace uses "number of points" - presumably because specifying both timespan, and timestep might result in non-integer number of points (poorly defined). - So... in this case, I want *timespace* to use the first argument (ignoring tstart) to dictate which algorithm to select. For example: with timespace(ts=1, tfund=20.5), the sampling period, ts is assumed to be exact, and the fundamental period (tfund) will be adjusted to get an integer number of points. - It would be preferable to use Juila's dispatch system to dispatch on the keyword names (which it does not - at least not directly). - Since *all *arguments here are keywords, Julia will only support a single master function "timespace(; kwargs...)". *Attempted Solution* I have a solution, but it depends on keyword ordering... and I don't know if this is a dangerous thing to do: I believe keyword ordering is *not* guaranteed. Anyways, here is the solution... #Dispatchable keyword type (make name short - expect heavy use) immutable KD{Symbol}; end #Not kraft dinner #Convert kwargs to a list of dispatchable elements: function dispatchable(kwargs::Vector{Any}) result = Any[] for (k,v) in kwargs push!(result, KD{k}()) push!(result, v) end return result end timespace() = throw("timespace requires arguments") timespace(;tstart=0, kwargs...) = timespace(dispatchable(kwargs)..., tstart=tstart) function timespace(::KD{:ts}, ts, ::KD{:tfund}, tfund; tstart=0) println("FUNCTION1 (priority on ts): ts=$ts, tfund=$tfund, tstart=$tstart") end #Similar to previous, but expects fs = 1/ts function timespace(::KD{:fs}, fs, ::KD{:tfund}, tfund; tstart=0) println("FUNCTION1.1 (priority on fs): fs=$fs, tfund=$tfund, tstart=$tstart") end function timespace(::KD{:tfund}, tfund, ::KD{:ts}, ts; tstart=0) println("FUNCTION2 (priority on tfund): tfund=$tfund, ts=$ts, tstart=$tstart") end This solution works (for the time being). The generic timespace(;kwargs...) function catches all the keyword argument, and converts the to normal arguments. After that, Julia's dispatch system finds the appropriate specialization. *Problem* The problem is that I don't know how safe it is to rely on the order of the keyword arguments, as done here. Is there maybe an alternative solution to this problem that would still keep the solution/naming succinct and easy to understand? (NOTE: this might be better suited for julia-dev, because it has to do with the intended use of the keyword arguments) I hope someone out there has an answer, or a better solution to this problem. Regards, MA
[julia-users] Re: [ANN] JuliaIO and FileIO
Thanks for that Simon. I think I did see the query() function... But it did not register until now. Indeed, I would prefer hierarchy in my file types... but experience tells me that's not trivial. Sometimes there are more than one useful hierarchies, so building a useful one can be difficult (I gave it my best shot for now). The "Union" solution: I am sort of reluctant to use unions (I don't quite find it as elegant as the inheritance system). Also, there is a change in Union syntax from v0.3->v0.4. But, since Julia's current release is finally at v0.4, I should really migrate ASAP. That being said, I still like your suggestion: The good thing about your Union solution is that it allows the *user* to select which filetypes are grouped, and how. I must give this serious thought. As for the dynamic loading: I can't really comment yet. I will have to get used to that system a bit more before I can have a real opinion. Regards, MA
[julia-users] Re: [ANN] JuliaIO and FileIO
Hi Simon, Thanks for the comments. >In the end, I would rather like to have the hierarchy in the Julia objects that get returned by load (e.g. AbstractString <: UTF8String etc) Hmm... Did not think of this... I guess because an encoding is not technically a string, but maybe that does not matter... >- There are many IO libraries which should get dynamically loaded when the format is detected (first argument for registry) I don't think I really understand this part... I usually like to explicitly pick which libraries I want my program to use... But it looks like FileIO auto-loads libraries. I'm not saying this is necessarily a bad thing... I'm just not used to thinking that way. >- we utilize magic bytes to recognize file formats (second argument for registry) Indeed that part is great! I just don't need it at the moment - because with the code I am writing (right know) I already know the file type. That said: I *know* I can make use of the magic byte detection in the future. Thanks for that! >- there are multiple IO libraries for the same formats and we need to choose one dynamically. Maybe that's one of the things I don't get fully... I would expect that if you have two PNG reader libraries: using MyPNGLib or using ThisGuysEvenBetterPNGLib Then, whichever library was "using"d should have registered itself with FileIO, and would then be used when the user calls: img = load(File{format"PNG"}("thisimage.png")) >>but something seems a little off about how I use/generate objects >I'm not really sure what you mean by that. Indeed... I'm not sure either... I'm trying to figure that out: At the moment, one thing I can think of are issues I expect when building an image editor program: module MyImageEditor #Think of something like GIMP #This would be a high-level open function that does everything necessary to #"open" the file to a new canvas: function open{T<:PixelImageFormat}(file::File{T}) data = FileIO.load(file) #Create new canvas #Populate canvas with data #Show canvas end function open{T<:VectorImageFormat}(file::File{T}) #Ask user what resolution they want for the rendered bitmap data = FileIO.load(file) #Create new canvas #Render vector image to canvas #Populate canvas with data #Show canvas end #For any other file: function open{T}(file::File{T}) throw("Cannot open this kind of file... not a (recognized) image") end #When the user clicks "ok": function imgopendlg_ok(dlg::ImgOpenDlg) #I assume FileIO could have an "autodetect" function that tries to #determine the most likely file type from the extension, then confirm #everything is ok using magic byes file = FileIO.autodetect(dlg.filepath) #Now file is a File object with type information. try open(file) catch e display_message(e) end end end #module As far as I can tell: If I were to try to open a large movie instead of a pixel image, I expect the following issues: 1) The current implementation of FileIO will try to auto-load the movie libraries I don't want to include with my program (because the code to register file readers is actually *inside* the FileIO module?? - I think?) 2) I would have to wait until my program has loaded the movie file before I can detect it was a movie file, and *then* I can finally catch it as an exception: function open(file::File) #In MyImageEditor data = FileIO.load(file) if !isimage(data) throw("Cannot open this kind of file... not a (recognized) image") end #Create new canvas #Populate canvas with data #Show canvas end isimage(data::PNGData) = true isimage(data::BMPData) = true ... isimage(unknowndata) = false ...Or something similar. To be fair: I am almost certain the the biggest reason for my unease with FileIO is that I have not seen enough examples on how to use the module properly. Can you point me to good example projects/other modules that use FileIO as intended? I am only getting a vague feel for its use by reading the included tests. Otherwise: I guess I will wait until more examples are available - or keep trying to play around with FileIO's capabilities when I have time. Best Regards, MA
Re: [julia-users] Re: [ANN] JuliaIO and FileIO
Hi all, I myself have met a similar need for a file object. That way, I can use the dispatch engine to overload the open function: f = File(format"test.jpg") s = open(f) instead of what I consider to be less attractive solutions: f = "test.jpg" s = open_jpeg(f) #or s = MyModule.open(f) #My module's JPG reader I like the idea of the FileIO module, but I am less a fan of having to register new filetypes with the module. ...Yet I must admit there is something nice about how FileIO appears to automate type creation (Sorry: I do not fully understand the module yet). I played a bit with FileIO, but something seems a little off about how I use/generate objects (I'm not sure why that is, though). Anyways, I tried getting similar functionality (attempts at solving my own problems dispatching read/open on different file types) by relying more heavily on the Julia type system: https://github.com/ma-laforge/FileIO2.jl Comments: - FileIO2 does not have as many bells & whistles as FileIO - but I think it has potential for that. - FileIO2 even has facilities to dispatch on different file encodings (ex: binary, UTF8, ASCII, ...) if one would desire such a thing (Though I prefer not to do so, in most cases). Sample Code: #Generate a reference to a text file: file = File{TextFmt}("generictextfile.txt") #Easily display the entire contents of an ASCII file: typealias ASCIIFile File{ASCIIFmt} #For convenience print(read(ASCIIFile(@__FILE__))) ...So I figured I would just put this out there in case the FileIO group finds something of value in the FileIO2 solution. MA
[julia-users] Re: Defining a function in different modules
Hi David, Thanks for the sample code. I must admit this is not exactly what *I* am looking for, but it is very interesting. I am not particularly good with macros code that deal with symbols... so this is very appreciated. I think there are enough elements here to achieve the effect I am looking for myself. I will see if I can get some time to try it out myself... But I don't see that happening for a little while. Thanks. On Sunday, May 3, 2015 at 7:00:04 PM UTC-4, David Gold wrote: Hi folks, I've been working on implementing the merging functionality that Jeff Bezanson noted earlier in this thread. For those interested, the project can be found here: https://github.com/davidagold/MetaMerge.jl. People should feel free to do whatever they find useful (if anything) with the code. Here's an example of it in action in Julia 3.7: [...]
Re: [julia-users] Defining a function in different modules
*Need help creating my package!* I am writing a program to perform a Monte-Carlo simulation of a plane's normal vector in Julia. I want to publish my Geometry package for others to use it... because it is awesome! Please do not ask me why I would want run such a simulation. Also: please don't ask why my code is so inelegant (using simple Vectors instead of defining a Coordinate type). It is a secret. All I can say is that I will make billions of dollars selling this to people in a parallel universe where everybody is high... all the time. I am following this thread because I see people having similar problems to mine. But apparently, there are no issues reported by the developers of the major Julia packages... so I am willing to accept I am doing something wrong. I just want someone (anyone) to tell me what that is (I just can't figure it out). Here is part of my program: #I'm running Monte-Carlo, so I need that awesome Distributions package: using Distributions #This is my awesome Geometry module that I want to distribute to others: module Geometry #I define a plane with 3 points... because using its normal is for suckers: type Plane point1::Vector point2::Vector point3::Vector end #Then I waste the CPU's time computing the normal... 'cuz I'm awesome: Normal2(x::Plane) = cross(x.point2-x.point1, x.point3-x.point1) export Plane export Normal2 end #Of course, I want to use that module using Julia's great succinct syntax: using Geometry #Bet you can't guess why varying the z-coordinate will make me billions of dollars!: #That's why I am a genous: function varyzdim(x::Vector, amount::Number) result = copy(x) result[3] *= 1+amount return result end #Principal algorithm: function simulate_monte_carlo(nruns::Integer) plane = Plane(Float64[0,0,0], Float64[1,0,0], Float64[0,1,0]) n = Normal2(plane) dist=Normal(0, .01) return [varyzdim(n,x) for x=rand(dist, nruns)] end #Step 1: Run simulation result = simulate_monte_carlo(3) @show result #Step 2: ... #Step 3: Profit! :Done *Problems:* - I was not able to call Geometry.Normal2 as Geometry.Normal... because it collided with Distributions.Normal. - I *could* define Normal(x::Plane) to extend Distributions.Normal... but then my friend will not be able to use my awesome module. Apparently, the universe where *he* is selling his software will be destroyed by Schrödinger's cat if the code is not deterministic. He tells me the cat will loose it or something... I don't know... I don't think I really care as long as he is happy. - In any case, I don't *want* to extend Distributions.Normal, because Geometry.Normal is very much orthogonal to the former. - I guess it would work if Normal was defined in Base... I mean pretty much *everybody* will want to use Julia's Base module anyways But it's not really practical for me to fork Julia just to add method Normal to module Base. - If I decide to keep the method name as Normal2... how do I know no other module out there won't try to use the same workaround as mine? Then I will not be playing nice with *that* module (I am getting a little anxious now...). - I could write this in C++... But I don't think I have the patience anymore (after getting hooked on Julia). *So what am I missing here?* 1. Am I doing something wrong? What is it about Julia's module system that I am not understanding. 2. Am I being too fussy? Is it unreasonable for me to expect that my Monte-Carlo simulation can take advantage of multi-dispatch on *both* Geometry.Normal and Distributions.Normal without needing to explicitly import Normal from their respective modules? 3. Is this case not considered common enough to warrant improvements to Julia's module/namespace system in the future? Should I accept that the best solution in the long term is to only import Geometry. Is the best solution to explicitly qualify my version of Normal as Geometry.Normal whenever two modules export the same symbol... despite having un-ambiguous signatures (AFAIK)? 4. Am I wrong about not being able to extend Base? Is it in fact possible for me to extend base in order to add the symbol Normal without forking? ...But then what do I do about having broken the Distributions module (because Base would then own Normal)? *Please! I would appreciate the input of *anyone* who can help me make the Geometry package work harmoniously with other packages (present future) in Julia's ecosystem.* PS: I could understand if a solution to this problem is non-trivial... I can also understand if this is simply not a high priority for the core team right now... But that's not the principal message I am getting from this thread at the moment.
Re: [julia-users] Re: Defining a function in different modules
Hi Lex, I think we agree here. I also got the same impression as you regarding your statement it might be possible for Julia to determine that there is no overlap between the methods simply, it is my understanding that in general it could be an expensive whole program computation. For me, I think this impression is derived from one of Jeff's posts: Comparing method signatures is computationally difficult (exponential worst case!), while looking for a symbol in a list is trivial. Warnings for name conflicts may be annoying, but at least it's dead obvious what's happening. If a subtle adjustment to a signature affects visibility elsewhere, I'd think that would be much harder to track down. ...But I am not absolutely certain I am following some of this discussion correctly
Re: [julia-users] Re: Defining a function in different modules
*Scott and Michael:* I am pretty certain I understand what you are saying, but I find your examples/descriptions a bit confusing. I think (hope) I know why Stafan is confused. *Stefan:* I think Scott has a valid point but I disagree that exported functions from a module must reference types defined in that module. It is my strong belief that Scott is merely focusing on the symptom instead of the cause. Fortunately, I am certain that this is not the crux of the problem... And I agree completely with Stefan: Limiting exports to this particular case is extremely restrictive (and unnecessary). I also agree that, this restriction *would* keep developers from developing very useful monkey patches (among other things). So let's look at the problem differently... *Problem 1: A module owns its verbs.* See discussion above discussion ( https://groups.google.com/d/msg/julia-users/sk8Gxq7ws3w/ASFlqZmVwYsJ) if you are not familiar with the idea. *Problem 2: Julia has 2 symbol types (for objects/methods/...)* Well, this is not really a problem... It is terrific! Julia's multi-dispatch engine allows us to overload methods in a way I have never seen before! In fact, the multi-dispatch system allows programmers to DO AWAY WITH namespaces altogether for the new type of symbol (at least to a first order). *So what are the symbol types?* 1) Conventional Type: Used in most other imperative languages 2) Multi-Dispatch Type: Symbols of methods whose signature can be uniquely identified. By this definition, if a symbol is not associated with a unique signature, it is simply a conventional symbol. And, as defined, conventional symbols run a high potential for signature collisions... because the signature is insufficient to uniquely identify whether we are referring to Foo.CommonSymbol(???) or Bar.CommonSymbol(???). *So why do we need namespaces?* Namespaces were created to let programmers use succinct symbol names without the problem of running into never-ending name collisions. Instead of dealing with symbol bloat (Foo.FoosSpecialSymbolThatCannotCollideWithAnybody) - we use scopes to give symbols a nice hierarchy (namespaces are basically named scopes). When writing code in the native scope, all symbols are nice and short... and you can even *import* the symbol names to your own scope to interact with the module. Now the user gets to use short names - not just the module developer! *So what about the multi-dispatch-ed symbols (type 2)?* Technically, they could *all* be located at the global scope. You don't really need to say Foo.run... because the call signature is unique (by definition) - so there is no ambiguity. *Ok, then where is the problem for module developers?* Simply put: Julia is trying to cram those beautiful multi-dispatchable methods into a construct (namespaces) that *is not technically needed* for type 2 symbols. As a consequence, the current Julia implementation actually makes it *difficult* for module developers to use multi-dispatch. Of course, everything is just peachy when you work from within Base :). Unfortunately, I believe this has caused a little more collateral damage: Since it is easier to work within Base, it has become this sort of god module. I believe Jeff has mentioned developers are getting reluctant to make it grow any further. *The Distributions module: Can it remain elegant?* The short answer is yes :)! Stefan has a valid concern: you either have to keep using full symbol paths (Distributions.Normal), or [...] you'd have to explicitly import every Distributions type and generic stats function that you want to use. Instead of being able to write `using Distributions` and suddenly having all of the stats stuff you might want available easily, you'd have to keep qualifying everything or explicitly importing it. Both suck for interactive usage - and frankly even for non-interactive usage, qualifying or explicitly importing nearly every name you use is a massive and unnecessary hassle. I agree. We don't want this... what a pain! Let's not go there. *So where do we start?* In this case, Normal is a relatively common name, and I cannot say its argument list is sufficiently unique to qualify it as a type 2 method. The signature only involves two ::Number arguments. Good rule of thumb: If an argument list is made up solely from base types (number/char/string/...) is likely to collide with a function in another module (say, a Geometry module). That was easy!: That means Normal is a type 1 symbol. As such, Normal *should* be export-ed by module Distributions... Nothing changes in the implementation! *Now how do we generate numbers with a normal distribution?* The Distributions package includes a rand() function. Interestingly enough, the signature for rand makes it a type 2 method - and so it has a very low probability of signature collisions. Here is a simplified definition of the rand function (Not using
Re: [julia-users] Re: Defining a function in different modules
Stefan, I am sorry, but my experience leads me to disagree with your statement that Julia is unable to dispatch a function dynamically (@ runtime). Quote included: module Foo export f immutable F end f(::F) = this is Foo end module Bar export f immutable B end f(::B) = this is Bar end julia using Foo, Bar julia f(rand(Bool) ? Foo.F() : Bar.B()) # which `f` is this? Which `f` is intended to be called here? It cannot be statically determined – it's not well-defined since it depends on the value of rand(Bool). Some dynamic languages are Ok with this kind of thing, but in Julia, the *meaning* of code should be decidable statically even if some of the behavior may be dynamic. Compare with this slightly different version of the above code (works on 0.4-dev): Indeed, running this code, I get a misleading error message. Whenever the code tries to run f(Foo.F()), I get the following message: ERROR: `f` has no method matching f(::F) *Here is the problem:* The error actually happened when Bar tried to declare f() - which was already exported by Foo, then using-d by the module user. So, in order to play nice, Bar would have to extend Foo.f()... even though (in an ideal world) Bar should never need to know that Foo owned f(). To make matters worse (on v.0.3.6), Bar then takes control of f() - and steals it from Foo... as a warning - not an error. To make my case, I submit a workaround for this example: #Sorry: My version of Julia does not have rand(Bool)... Base.rand(::Type{Bool}) = randbool() module Foo export f immutable F end f(::F) = this is Foo end module Bar #export f #Nope... cannot do this... Foo defined first: it owns f immutable B end #Sad but true: Foo owns f... so we must adhere to this reality: import Foo Foo.f(::B) = this is Bar end using Foo, Bar #No problem... Julia has an algorithm to dispatch functions #even if the compiler cannot resolved the call statically. #Of course, a statically resolved dispatch would be faster than a dynamic one... for i in 1:10 println(f(rand(Bool) ? Foo.F() : Bar.B())) end ...So your statement confuses me a little... On Wednesday, April 29, 2015 at 4:41:38 PM UTC-4, Stefan Karpinski wrote: Tom, this is a very legitimate concern. A simple solution is to have a coding standard not to use `using` when writing packages. Google has created coding standards for both C++ and Python, which are now widely used beyond the company. Automatic function merging goes in the opposite direction: with this feature it becomes impossible to even say which package a function comes from – it's not even a meaningful question anymore. That is the point of Jeff's Base.sin versus Transgression.sin example – map(sin, [1.0, greed, 2pi, sloth]). There is no answer to the question of which of the function Base.sin and Transgreassion.sin the `sin` function refers to – it can only refer to some new `sin` that exists only in the current module and calls either Base.sin or Transgressions.sin depending on the runtime values of its arguments. Perhaps this can be made clearer with an even nastier example, assuming hypothetical code with function merging: module Foo export f immutable F end f(::F) = this is Foo end module Bar export f immutable B end f(::B) = this is Bar end julia using Foo, Bar julia f(rand(Bool) ? Foo.F() : Bar.B()) # which `f` is this? Which `f` is intended to be called here? It cannot be statically determined – it's not well-defined since it depends on the value of rand(Bool). Some dynamic languages are Ok with this kind of thing, but in Julia, the *meaning* of code should be decidable statically even if some of the behavior may be dynamic. Compare with this slightly different version of the above code (works on 0.4-dev): module Sup export f f(::Void) = nothing # declare generic function without a la #8283 https://github.com/JuliaLang/julia/issues/8283 end module Foo export f import Sup: f immutable F end f(::F) = this is Foo end module Bar export f import Sup: f immutable B end f(::B) = this is Bar end julia using Foo, Bar julia f(rand(Bool) ? Foo.F() : Bar.B()) Why is this ok, while the previous code was problematic? Here you can say which `f` is called: Foo and Bar share `f` so the answer is well-defined – `f` is always `Sup.f`.
Re: [julia-users] Re: Defining a function in different modules
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.
Re: [julia-users] Re: Defining a function in different modules
I am not sure I understand Scott's last comments, but I first want to correct something from my last entry. Sorry about the last entry: 2) using seems to pull names/symbols into the global namespace/scope (Main?) instead of the local one (whichever module the code resides). 3) Module developers export functions that cannot be resolved by multiple dispatch. Statement 2 is wrong (I have not thought of this in a while). I would like to re-state it: 2) using seems to apply at the module-level. I think dealing with name collision would be much easier if using applied to arbitrary scopes. Also, I should point out that I only know how to deal with item 3 through good programming practices, again, as outlined in: https://groups.google.com/d/msg/julia-users/O8IpPdYBkLw/XzpFj9qiGzUJ Again, my apologies.
Re: [julia-users] Re: Defining a function in different modules
Hi, I cannot speak about limitations during the compile process, but at a high level, I don't see why (with a few small tweaks) Julia's multiple dispatch system cannot deal with most of the issues discussed here. From what I see, there appears to be 3 issues that cause most of the headaches: 1) A module seems to own a function. 2) using seems to pull names/symbols into the global namespace/scope (Main?) instead of the local one (whichever module the code resides). 3) Module developers export functions that cannot be resolved by multiple dispatch. I believe items 2 3 are well covered in Using ModX: Can scope avoid collisions improve readability?: https://groups.google.com/d/msg/julia-users/O8IpPdYBkLw/XzpFj9qiGzUJ As for item 1, the next section should provide clarification: *A module seems to own a function* Well, my biggest problem is that if you want to reuse the word open for your particular application, you need to re-implement base.open(...). This requirement seems a bit awkward. Should you not just be able to implement your own MyModule.open as long as it can uniquely be resolved through multiple dispatch? In that case applying using Base using MyModule should be able to merge the two open functions without ambiguity... as long as Base.open was defined with an interface that is unique: #Sample Base module: module Base abstract Stream abstract FileType : Stream type BinaryFile : FileType ...; end function open(::Type{BinaryFile}, ...) ... end export Stream, FileType, BinaryFile export open end #Base #Implement my own socket communication: module MySocketMod type MySocket : Base.Stream ...; end function open(::Type{MySocket}, ...) ... end export MySocket export open end #MySocketMod #Try out the code: using Base using MySocketMod #No problem... open ambiguities are covered by mulit-dispatch. #Great! No abiguities: myfile = open(BinaryFile, ...) mysocket = open(MySocket, ...) Sure, the extra argument in open *seems* a bit verbose compared to other languages, but it is a bit easier to read... and the argument *not* really redundant. Indeed, I can see that this solution would require extra compiler complexity - depending on which items are being addressed: A) Merging function specializations from different modules might have to be done at run time - not ideal. B) using/importing module functions in a local scope makes the symbol tables much larger - not great either. Having said that, I don't see actual ambiguities here, only additional complexity in the implementation.
[julia-users] Re: Using ModX: Can scope avoid collisions improve readability?
ele...: I did not know about this sys.modules thing. Good to know. Josh ele...: Agreed. I don't think pollution happens until the using modX call happens. So, I don't really understand why we can't have scope-level using commands. And yes, maybe Julia *should* use a different keyword than using when applied to arbitrary scopes (as opposed to when we use it at the module-level). ...So linking back to Patrick's comment: The export list sort of tells the module user what functions are meant to be used. It just happens that Julia's implementation of using pulls in all export-ed elements into the current module namespace. This works extremely well with the multi-dispatch engine. However, I can also see a place for a slightly weaker directive: Let's call it provide for now. The provide directive could be used to tell the user what other elements (like constructors) are supported by the module. The provide-ed elements would not be pulled in by the using statement. Only export-ed values do that. Instead, provide-ed elements would *only* be pulled-in when a user calls using namespace modX (or some other keyword). This would allow developers to use shorter names. Names that would otherwise collide if they were to be export-ed: module Electroncis type Circuit name::String elemlist::Array{CktElem} ... end abstract IndepCktElem abstract drivePattern type Vsrc : IndepCktElem ...; end type SineWave : drivePattern ...; end connect(c::Circuit, x::CktElem, n::NodeList) = ... drive(c::Circuit, x::IndepCktElem, n::NodeList, p::drivePattern) = ... ... export connect, drive #No problem: Can be handled by multi-dispatch provide Circuit#Dangerous: Cannot always be resolved by multi-dispatch provide Vsrc, SineWave #Also a little dangerous end Now, in the user's module, you can do the following: using Electronics #Brings in connect drive, as usual #Eventually gets a little verbose when dealing with elements that cannot easily #be resolved by multi-dispatch (provide-ed elements): function make_circuit() c = Electronics.Circuit(Myckt) drive(c, Electronics.Vsrc(), [:SUPPLY, :GND], Electronics.SineWave(1e9)) return c end #But this function *could* be made more succinct: function make_circuit2() using namespace Electronics #Also brings in all other legitimate elements c = Circuit(Myckt) #More succinct constructor call #Things gets even nicer with more complex expressions: drive(c, Vsrc(), [:SUPPLY, :GND], SineWave(1e9)) return c end On Friday, March 6, 2015 at 6:36:44 PM UTC-5, ele...@gmail.com wrote: This is essentially the method used by Python (as I believe I understand it, import is the worst documented thing in Python). Python puts a reference to all modules into sys.modules, no matter where they are imported. And sys.modules is always the first thing searched before path. So all modules are imported and initialized once (excepting users explicitly deleteing or reloading). An no matter where the imports happen the first will actually load and initialize the module and all the others will just use that copy. But since modules are referenced by sys.modules, not the top level namespace, there is no pollution until a user explicitly imports into that namespace. On Saturday, March 7, 2015 at 5:48:11 AM UTC+10, Josh Langsfeld wrote: So then your results would indicate that putting 'using MyModule' inside a function *could* actually bring the exported names into only the local scope *if* the module had already been constructed in the global scope. I know I've seen some people discuss name pollution by 'using' too many modules. It might be part of a wider solution to enable local scope 'using', either with a new keyword or just having 'using' check if the module already exists.
Re: [julia-users] Re: Functions in degrees
Fair enough. I don't want to stifle the adoption of Julia by other developers. Maybe Ivar is correct: This might be better suited to be implemented as a 3rd party library. Maybe SIUnits (https://github.com/Keno/SIUnits.jl) On Wednesday, March 4, 2015 at 9:04:30 AM UTC-5, Patrick O'Leary wrote: On Tuesday, March 3, 2015 at 2:57:28 PM UTC-6, Stuart Brorson wrote: Since types should be used sparingly, I don't think it a good idea to replace convenience functions like sind and cosd with a type-driven invocation mechanism -- ordinary users will be confused. You also can't replace all of them, since the inverse functions can't be dispatched in this way. Anecdotally, I use atan2d more than any of the other *d functions, typically as a step on the way to making a plot.
[julia-users] Re: Using ModX: Can scope avoid collisions improve readability?
Josh: I do not fully appreciate the details of how modules get imported either. Here is what I can gather: module moda export modvar, setmodvar modvar = 1 setmodvar(x) = (global modvar=x) end module modb export modvar, setmodvar modvar = 2 setmodvar(x) = (global modvar=x) end module modc using moda import modb println(using moda) @show modvar, moda.modvar, modb.modvar @show setmodvar(5) @show modvar, moda.modvar, modb.modvar @show modb.setmodvar(3) @show modvar, moda.modvar, modb.modvar end module modd import moda using modb println(using modb) @show modvar, moda.modvar, modb.modvar @show setmodvar(8) @show modvar, moda.modvar, modb.modvar end This gives the following results: using moda (modvar,moda.modvar,modb.modvar) = (1,1,2) setmodvar(5) = 5 (modvar,moda.modvar,modb.modvar) = (5,5,2) modb.setmodvar(3) = 3 (modvar,moda.modvar,modb.modvar) = (5,5,3) using modb (modvar,moda.modvar,modb.modvar) = (3,5,3) setmodvar(8) = 8 (modvar,moda.modvar,modb.modvar) = (8,5,8) So it looks like it is the same code in the background (at least the variables appear to be in a common address space). So... it looks like import merely makes visible the code at a module level... And using first imports, then provides a shortcut to the exported variables/functions... But as far as I can tell, compilation is done on demand. I believe that the real compile step is done when we call a particular version of the code. Compilation is actually a separate step from using and import On Tuesday, March 3, 2015 at 11:48:53 AM UTC-5, Josh Langsfeld wrote: I'm curious about that workaround suggested in the FAQ, where you wrap the function inside its own module. What is happening under the hood there? Does it reinitialize the desired module entirely inside of the wrapper module or does it just make a reference to some other compiled and initialized top-level area? This is assuming the module has already been built elsewhere and you just want easy local access to the exported symbols. On Monday, March 2, 2015 at 5:59:30 PM UTC-5, ele...@gmail.com wrote: The C++ using namespace and Julia using module are not quite the same thing. The C++ namespace is a top level entity that is created and initialized as part of the C++ startup code and the using just makes the names of these global entities available within the scope. The Julia using imports, and thus creates, the module for the first time, and Julia modules can contain statements that run at initialization, whereas C++ namespaces can only contain declarations. But if the Julia using is within the function, when should the actual import and initialize and execute the statements be done? Every time the function is called is very expensive. Hoist the import out of the function to the top level, but doing this naively (ie putting the hoisted import just before the function) will then affect all code following the function Have a pseudo top- level visible only to the function adds a complete new complication to the name management code. But then what happens if the module is imported into two functions, how is its initialization managed? Or the top level and the function? So for now the simpler is better approach is to have the user manage importing at the top level only. Cheers Lex On Tuesday, March 3, 2015 at 7:23:33 AM UTC+10, Josh Langsfeld wrote: It's discussed in the FAQ so there must be a good reason for it, though no rationale is mentioned. http://docs.julialang.org/en/latest/manual/faq/#can-i-use-using-or-import-inside-a-function On Monday, March 2, 2015 at 3:00:21 PM UTC-5, Patrick O'Leary wrote: On Saturday, February 28, 2015 at 11:06:38 AM UTC-6, MA Laforge wrote: C++ provides using namespace X to make available the contents of X to the current scope. This even works on un-named scopes within a function: (etc.) I know this is something that's come up before, and I think rejected--I think because it causes conflicts with multiple dispatch? But I can't seem to find the thread(s). I can't create a hard conflict in a quick mental search for an example, but I can create some level of confusion: module Foo bar::Int = 1 end module Baz bar::Float64 = 27.3 with module Foo # not current Julia syntax bar #which bar is this? end end
[julia-users] Re: Using ModX: Can scope avoid collisions improve readability?
Indeed this appears to be the intent: export tells the user what you want to be his/her interface. But I have also noticed myself omitting exports in order to avoid collisions with elements that cannot be resolved by multi-dispatch (like type constructors): module Electronics type Circuit ... end #Name is very common... don't export end module RailSystem type Circuit ... end #Name is very common... don't export end using Electronics using RailSystem #No collision with Circuit: because it is not exported eckt = Electronics.Circuit(rectifier) railckt = RailSystem.Circuit(Line A) Otherwise, I would have to use more verbose names (which just seems silly to me): Electronics.Circuit - Electronics.ElectronicCircuit #Not a common name: should be ok to export RailSystem.Circuit - RailSystem.RailCircuit #Not a common name: should be ok to export ...And maybe that's simply how modules should be defined: Never export elements that cannot be resolved by multi-dispatch. On Tuesday, March 3, 2015 at 8:52:20 AM UTC-5, Patrick O'Leary wrote: On Monday, March 2, 2015 at 7:45:02 PM UTC-6, MA Laforge wrote: Your comment sounds alot like what Stefan said: https://groups.google.com/d/msg/julia-users/UvBff9QVKaA/P10-LRLezCUJ I admit I don't fully appreciate why this is a *technical* problem. Most scoping rules would dictate that you should be referring to the *most local* version of the value. In your case bar would come from module Foo. One counterargument to that is that it makes the most local thing nonlocal--it's an unexported part of Foo. The export list is in part a declaration of I'm okay with these things sharing namespace if you want, and if you did `export bar` from Foo, then `import Foo`, you'd get what you wanted. (There's a side discussion about things happening inside functions; I'm not concerned about that here because that can only make things more complicated.)
Re: [julia-users] Re: Functions in degrees
:+1 That's a good point. I have myself experienced problems calculating mean when periodicity is not taken into account. As for dimensionless quantities: I see no issue assigning a type to them (other than a potential re-design of the Julia libraries... gross). In fact, I expect alot of convenience with *typical* use cases. The real question is how much programming overhead is required to use these types (assuming the compiler does the grunt work reducing the *performance* overhead). For example, you can easily/quickly obtain typeless values with val: abstract Unit val(x::Unit) = x.v abstract Angle : Unit immutable type Radians{T:Number} : Angle v::T end unitlessVal = val(Radians(pi)) (See: https://github.com/ma-laforge/testcases/blob/master/units_test/units_test_angles.jl ) On Monday, March 2, 2015 at 8:14:27 AM UTC-5, Yuuki Soho wrote: One advantage of having a Radian type would be to have circular statistics built-in, mainly mean, var, std or cor. Other languages usually have special functions or packages for that (circmean).
[julia-users] Re: Using ModX: Can scope avoid collisions improve readability?
Indeed. I think that is the problem: Julia's using statement is tightly coupled to the module import functionality. From my understanding, the C++ using namespace N1::N2::N3 directive simply informs the compiler to use shorthand notation for all variables/functions present in namespace N1::N2::N3. You do not actually Import anything new. In fact, with C++: the contents of that module are usually compiled independently in another library file anyways. I don't think the using directive affects the linker either (at least not directly). On Monday, March 2, 2015 at 5:59:30 PM UTC-5, ele...@gmail.com wrote: The C++ using namespace and Julia using module are not quite the same thing. The C++ namespace is a top level entity that is created and initialized as part of the C++ startup code and the using just makes the names of these global entities available within the scope. The Julia using imports, and thus creates, the module for the first time, and Julia modules can contain statements that run at initialization, whereas C++ namespaces can only contain declarations. But if the Julia using is within the function, when should the actual import and initialize and execute the statements be done? Every time the function is called is very expensive. Hoist the import out of the function to the top level, but doing this naively (ie putting the hoisted import just before the function) will then affect all code following the function Have a pseudo top- level visible only to the function adds a complete new complication to the name management code. But then what happens if the module is imported into two functions, how is its initialization managed? Or the top level and the function? So for now the simpler is better approach is to have the user manage importing at the top level only. Cheers Lex On Tuesday, March 3, 2015 at 7:23:33 AM UTC+10, Josh Langsfeld wrote: It's discussed in the FAQ so there must be a good reason for it, though no rationale is mentioned. http://docs.julialang.org/en/latest/manual/faq/#can-i-use-using-or-import-inside-a-function On Monday, March 2, 2015 at 3:00:21 PM UTC-5, Patrick O'Leary wrote: On Saturday, February 28, 2015 at 11:06:38 AM UTC-6, MA Laforge wrote: C++ provides using namespace X to make available the contents of X to the current scope. This even works on un-named scopes within a function: (etc.) I know this is something that's come up before, and I think rejected--I think because it causes conflicts with multiple dispatch? But I can't seem to find the thread(s). I can't create a hard conflict in a quick mental search for an example, but I can create some level of confusion: module Foo bar::Int = 1 end module Baz bar::Float64 = 27.3 with module Foo # not current Julia syntax bar #which bar is this? end end
[julia-users] Re: Using ModX: Can scope avoid collisions improve readability?
Your comment sounds alot like what Stefan said: https://groups.google.com/d/msg/julia-users/UvBff9QVKaA/P10-LRLezCUJ I admit I don't fully appreciate why this is a *technical* problem. Most scoping rules would dictate that you should be referring to the *most local* version of the value. In your case bar would come from module Foo. On the other hand, I can envisage a scary situation arising by adding variables to the Foo module *after* the code for Baz has been completed verified. To avoid this potentially disastrous event: the Julia compiler might have to err out. On Monday, March 2, 2015 at 3:00:21 PM UTC-5, Patrick O'Leary wrote: I know this is something that's come up before, and I think rejected--I think because it causes conflicts with multiple dispatch? But I can't seem to find the thread(s). I can't create a hard conflict in a quick mental search for an example, but I can create some level of confusion: module Foo bar::Int = 1 end module Baz bar::Float64 = 27.3 with module Foo # not current Julia syntax bar #which bar is this? end end
Re: [julia-users] Re: Functions in degrees
I like that idea as well, but I would argue that radians should indeed have their own type *despite* being unitless. Julia's multi-dispatch system would make calling angle-dependent functions safer, and promote the use of shorter names. As an added benefit, unit conversion could be easily achieved on a function-by-function basis (I feel blanketed auto-promotion for units might be dangerous). I built a very simple mockup to try it out. I used Inch - Meter conversion as an example (hoping it might capture a broader audience), but I think it would deal perfectly with this very issue: https://github.com/ma-laforge/testcases/tree/master/units_test (see units_test.jl) I do not fully appreciate what would be needed to retrofit Julia's basic operations, but I would guess you could comment on that. On Wednesday, February 5, 2014 at 10:40:41 AM UTC-5, Stefan Karpinski wrote: What's particularly nice about having Degree and Turn and such is that you can apply the same exact generic code to any mixture of angular measurements in different units and still get the correct answers. I'm a little concerned about the need to redefine so many basic operations for angular quantities, but maybe that's ok. On Wed, Feb 5, 2014 at 10:38 AM, Stefan Karpinski ste...@karpinski.org javascript: wrote: I rather like the Degree type idea. Radians are unitless so they don't need a type – i.e. PiMultiple is just the default for all trig functions. You could, however, also have things angular units like Turns.
Re: [julia-users] Re: Functions in degrees
Good to know. The proposed method does not appear to have issues dealing with this. Multi-dispatch can still pick up the appropriate trig() function. See snippet I just added for angles: https://github.com/ma-laforge/testcases/blob/master/units_test/units_test_angles.jl As the code shows: Functions are easy to add once types are defined: Base.sin(x::Radians) = sin(val(x)) Base.sin(x::Degrees) = sind(val(x)) Base.sin(x::Angle) = sin(Radians(x)) Typed angles should help maintain a compact namespace (even if we include Revolutions as an angle). As for Stuart's comment: Maybe Julia modules should include a Matlab compatibility submodules to reduce clutter: module Trigonometry #Probably excessive ... module MatlabCompatibility ... end end module Algebra #Probably excessive ... module MatlabCompatibility ... end end using Trigonometry using Algebra using MatlabCompatibility On Sunday, March 1, 2015 at 5:00:24 PM UTC-5, Steven G. Johnson wrote: The errors in sin and cos can be much larger than 1ulp for sin or cos of large phase angles ( 360) in degrees, because pi is not exactly representable in fp while 180 is.
Re: [julia-users] Re: Functions in degrees
Oops. Please disregard comment on Matlab compatibility. I am almost certain Julia cannot support it in this way. On Sunday, March 1, 2015 at 11:46:49 PM UTC-5, MA Laforge wrote: Good to know. The proposed method does not appear to have issues dealing with this. Multi-dispatch can still pick up the appropriate trig() function. See snippet I just added for angles: https://github.com/ma-laforge/testcases/blob/master/units_test/units_test_angles.jl As the code shows: Functions are easy to add once types are defined: Base.sin(x::Radians) = sin(val(x)) Base.sin(x::Degrees) = sind(val(x)) Base.sin(x::Angle) = sin(Radians(x)) Typed angles should help maintain a compact namespace (even if we include Revolutions as an angle). As for Stuart's comment: Maybe Julia modules should include a Matlab compatibility submodules to reduce clutter: module Trigonometry #Probably excessive ... module MatlabCompatibility ... end end module Algebra #Probably excessive ... module MatlabCompatibility ... end end using Trigonometry using Algebra using MatlabCompatibility
[julia-users] Using ModX: Can scope avoid collisions improve readability?
Hi Julia developers, I am not sure where I should post this, so here goes... I am really impressed with the Julia language. It does many things well. But there is one aspect of C++ that I miss dearly: C++ provides using namespace X to make available the contents of X to the current scope. This even works on un-named scopes within a function: - See https://github.com/ma-laforge/testcases/blob/master/namespace_test/namespace_test.jl In Julia, the closest functional equivalent appears to be the using directive. However, my experiments show that using really only works at the module-level: - See https://github.com/ma-laforge/testcases/blob/master/namespace_test/namespace_test.cpp Admittedly, the overall module system in Julia is superior to C++ namespaces. I simply wish the using directive could be applied to arbitrary scopes. Scope-level using directives are particularly useful when the multi-dispatch system cannot resolve ambiguities. For example, an Imperial module might provide c in feet/s. *Effect on coding style* Without scope-level using directives, it seems impractical to rely on module hierarchy to limit the name length of factory elements (those unresolvable by Julia's multi-dispatch system): - See https://github.com/ma-laforge/testcases/blob/master/namespace_test/arm_objects.jl In C++, it is very natural and easy to use compact names for these factory elements (ex: classes/constructors/constants...): - See https://github.com/ma-laforge/testcases/blob/master/namespace_test/arm_objects.cpp *Questions* 1. Is there a subtlety of Julia's use model that I might be misunderstanding here? 2. If not: would it be feasible to implement scope-level using in Julia? *Note* I did notice others out there posting issues regarding namespaces and clobbering. One that stands out right now is a post by Edmund: - https://groups.google.com/d/msg/julia-users/T5YYKQzl-Cc/oJVwnMz9zroJ It appears these posts have died down lately. Indeed, Julia's current module system does provide reasonably adequate options. I just wanted to suggest a way to improve it slightly.
[julia-users] Using ModX: Can scopes avoid collisions improve readability
Hi Julia developers, I am not sure where I should post this, so here goes... I am really impressed with the Julia language. It does many things well. But there is one aspect of C++ that I miss dearly: C++ provides using namespace X to make available the contents of X to the current scope. This even works on un-named scopes within a function: - See https://github.com/ma-laforge/testcases/blob/master/namespace_test/namespace_test.jl In Julia, the closest functional equivalent appears to be the using directive. However, my experiments show that using really only works at the module-level: - See https://github.com/ma-laforge/testcases/blob/master/namespace_test/namespace_test.cpp Admittedly, the overall module system in Julia is superior to C++ namespaces. I simply wish the using directive could be applied to arbitrary scopes. Scope-level using directives are particularly useful when the multi-dispatch system cannot resolve ambiguities. For example, an Imperial module might provide c in feet/s. *Effect on coding style* Without scope-level using directives, it seems impractical to rely on module hierarchy to limit the name length of factory elements (those unresolvable by Julia's multi-dispatch system): - See https://github.com/ma-laforge/testcases/blob/master/namespace_test/arm_objects.jl In C++, it is very natural and easy to use compact names for these factory elements (ex: classes/constructors/constants...): - See https://github.com/ma-laforge/testcases/blob/master/namespace_test/arm_objects.cpp *Questions* 1. Is there a subtlety of Julia's use model that I might be misunderstanding here? 2. If not: would it be feasible to implement scope-level using in Julia? *Note* I did notice others out there posting issues regarding namespaces and clobbering. One that stands out right now is a post by Edmund: - https://groups.google.com/d/msg/julia-users/T5YYKQzl-Cc/oJVwnMz9zroJ It appears these posts have died down lately. Indeed, Julia's current module system does provide reasonably adequate options. I just wanted to suggest a way to improve it slightly.