3 ms·
There is something elegant about having all functions at the top level (or module) scope, `foo(x, y, z)`, but I there is also something really nice about functi
by rnikander 5y ago
There is something elegant about having all functions at the top level (or module) scope, `foo(x, y, z)`, but I there is also something really nice about function names scoped to the thing/noun/subject: `x.foo(a, b)`. As far as I know Julia only does the former. Sometimes the latter seems a lot easier to deal with.
- ivirshup 5y agoYou can do both. Check out the difference between `import` and `using`: https://docs.julialang.org/en/v1/manual/modules/ https://docs.julialang.org/en/v1/manual/modules/
- blindseer 5y agoI think you mean you can do `foo(x, y, z)` instead of `M.foo(x, y, z)`. You cannot do `x.foo(y, z)` instead of `foo(x, y, z)`, a feature I sorely miss in Julia. Nim is awesome in this regard. There are some functions / paradigms that are just better represented by `x.foo(y, z)`. Chaining functions in particular in typescript / javascript / rust is SOOO nice. Specifically, in Julia a lot of times I want to create a immutable struct with multiple fields, many of which have defaults. In Julia none of ways seem clean to accomplish this. In rust, something like this is very common: let m = App::new("My Program") .author("Me, me@mail.com") .version("1.0.2") .about("Explains in brief what the program does") .arg( Arg::new("in_file").index(1) ) In Julia the same thing is: m = App("My program") m = author(m, "Me, me@mail.com") m = version(m, "1.0.2") m = about(m, "Explains in brief what the program does") m = arg(m, index(Arg("in_file"), 1)) I think with improvements to the pipe operator this can be better but right now I find this painful to read / write.
- sundarurfriend 5y ago> immutable struct with multiple fields, many of which have defaults With `Base.@kwdef` (or the enhanced `@with_kw` from Parameters.jl) on the struct definition, that example can be: m = App(name = "My program", author = "Me, me@mail.com", version = "1.0.2", about = "Explains in brief what the program does", arg = index(Arg("in_file"), 1) which seems pretty nice to me. Also, there's Chain.jl for a better pipe operator, though I agree improvements to the Base pipe would be great. To the original point, the problem with x.foo(y, z) is that it would be highly misleading in that it seems to suggest that x is somehow special to the dispatch of the call, which isn't true. While superficially it can feel more familiar, it would instead become a trap for people giving them a wrong mental model of the call's semantics.
- blindseer 5y agoThat uses keyword arguments though which is bad for performance, which is the main reason I'd like to use immutable structs.
- sundarurfriend 5y agoUnless you have some very weird use case (and probably even then), that sounds like a bad application of the "keyword arguments bad for performance" mental model. The reason to use immutable structs is better performance when you use them, not when you construct them - how often are you constructing new struct objects that the constructor performance is a significant issue? And if you are constructing many many thousands of objects to the level it becomes a performance concern, any difference from keyword arguments will be easily dwarfed by the cost of actually constructing the struct in memory. Also, these constructors ar simply passing on these named arguments to the non-keyword constructors. Anything complex you're doing during construction will be happening in the non-keyword constructors, and those do get specialized to have good performance; these keyword constructors are simply providing a small, simple interface to them, in a way that shouldn't affect performance in any measurable way.
- DNF2 5y agoI have never noticed them being bad for performance. Are you really sure?
- sundarurfriend 5y agoSince keyword arguments don't participate in multiple dispatch, they can't be used for compile-time specialization of methods based on their type. That can be a performance issue in specific scenarios, but I think they've taken that as a general rule and misapplied it here (as I mentioned in my sibling comment). For this scenario, that aspect of keyword arguments is most likely irrelevant.
- iib 5y agoI think the design trade-off was to aid with multiple dispatch, one of the core paradigms in Julia. There, the implicit bind in `x.foo(y, z)` does not make `foo` useful for multiple dispatching, so their hand was forced. They may have gotten this from the Common Lisp Object System.