`map(el->el^2, a)`
and inspired by Ruby
``` map(a) do element log(element) end ```
The latter being syntax sugar for the former.
Well...they're both method calls, aren't they? (So they're both the nicer way?)
>>> ', '.join(['1', '2', '3'])
'1, 2, 3'
>>> '1, 2, 3'.split(', ')
['1', '2', '3']I read the first as the concat symbol applied to an iterable leads to string concated by the concat symbol.
I read the second as an iterable broken by split symbol leads to an iterable of the chunks.
In the first case, I want to do something to a list: join it into a string. So, clearly, I need a list method? But no, I need to engage in some form of indirection; for some reason, I need to reach for a string method. Even if there is no string that I want to use as a delimiter. In that case, I need to use a string method on an empty string.
OK, I’ll play along. Now I want to take the string and split it into an array. Now that I’ve been educated, I know better than to try the sensible thing. Pre-enlightenment, I would have reached for a method applied to the thing that I wanted to transform. But now I know I should think backwards, and use a method applied to the delimiter. OOPs.
julia> join([1 2 3], ", ")
"1, 2, 3"
julia> split("1, 2, 3", ", ")
3-element Vector{SubString{String}}:
"1"
"2"
"3"
Note how they are both functions. The data that they operate on is the first argument, in both cases. The optional second argument is the obvious next most important thing, the delimiter. Other optional arguments come after that. There is nothing to remember, because it makes sense.You'll have to decide if you find that convincing. I understand your point and kind of wish I hadn't read this thread because I'm more torn than before.
This could have easily been avoided if `join` would have been a method of the list object, not the string object. But we're stuck with this now.
Maybe it would be better as a standalone function. But then you'd either have to import it or it would pollute the global namespace.
Other OOP models offer different solutions.
https://arstechnica.com/science/2020/10/the-unreasonable-eff...
Not in CLOS, from which Julia's mechanisms are derived (which leads to the question why not CLOS but Python of all things should be used as a source of "normal sense" of anything Julia-related). In CLOS, classes bind together data, generic functions name abstract operations, and methods represent specific code that deals with implementing a generic function for a particular combination of type arguments.
> which is what leads to all the problems
I don't think anyone is disputing that here. There's a reason why CLOS didn't do any of that.
> In Julia functions are generic, and specialized to methods acting on arbitrary combinations of types; they are freed from the data.
...yes, just like in CLOS (unsurprisingly, given Julia's heritage), and those types are effectively CLOS classes.
Although multiple dispatch in CL (and Perl) predates Julia, I was not aware that Julia’s design derived from it. Do you have a reference that traces this?
Interestingly enough, in Julia's documentation, the section "Noteworthy Differences from other Languages" (https://docs.julialang.org/en/v1/manual/noteworthy-differenc...) compares Julia to only several relevant languages, which are: Matlab, R, Python, C/C++, and...Common Lisp, of all things. I very strongly doubt that this is a coincidence.
Using the latest version (1.6 - although 1.6.1 just came out) the time to first plot is just a few seconds. After that, plotting in the REPL is instantaneous.
I probably don’t understand what you’re getting at when you speak of making frequent changes to code. REPL-based development in Julia is excellent, and there are Pluto notebooks as well.
I would run the code in repl (just using up-arrow and enter), get some plot, modify the code in the editor, save it, and rerun it repl.
Repl is used for connecting inputs to the program, not for editing. Often times you want to develop some small program that is part of a bigger program. So you run the big program up to the point it calls the small program. Or you run with some mock data. Then you have all your inputs for the small program, so you can start iterating it. Run - observe - edit - run - observe - edit.
In Matlab this worked because it detected if the file had changed, and reloaded it. You didn't specifically have to call load("my_function.m") before every call to it. This means you can just lift code from the big program and iterate on it in repl.
https://docs.julialang.org/en/v1/manual/workflow-tips/#Revis...
After using Ruby for years, returning to Matlab style code in Julia felt somewhat awkward. Instead of my_array.length you have length(my_array). In my personal preference the method call is just a nicer way of doing the same thing. The single-instruction-multiple-data or dot notation sometimes worked and sometimes didn't, so you had to resort to loops anyway.
Ruby and map or each have their verbosity but overall it feels a more robust "hammer" for general programming tasks. On the other hand, Julia can be really dense and still easy to understand.Other languages of course take some of these things even further. Maybe some day I will find an ergonomics and nicety first successor to both.
Plotting with two Y axes or generating histograms in Julia was also way harder than I remember it being in Matlab. Also manually having to load the file before every run to see the changes in action added a lot of overhead to the workflow.
The workflow I was used to in Matlab involved very frequent making changes to code, running of the code that usually made some plot. Which is one command in Matlab, and plotting was fast, in 2001 already, on Windows NT 4. In Julia, you have to first load the modified file, then run it. Plotting takes a long time. One just can't get nearly as productive with it in 2021, compared to Matlab of 2001 vintage.
What language would I pick if I had to do some quick analysis from some tables downloaded from the internet? Probably Julia still. If I had free access to Matlab, I would probably use it though.