News for hackers. Stuff that matters.
Re:Julia as a CLI Calculator by RivieraKid on Friday June 05, 2020 @09:29AM (#23428253)
I really wish there was a language based on Swift that would include most of the nice language, REPL and library characteristics of Julia (and perhaps few from Dart). That would get really close to a "perfect language" for me.

Overall I like Julia - and use it as a CLI calculator as well - but there are several things that prevent it from being a good general purpose language:

- OOP support is "meh".

- str.parse(Int).abs is more readable than abs(parse(Int, str)). And this is a very simple case, the readability difference is greater in more complex expressions.

- 1-based indexing.

- Lack of good support for nullability, think of "if let", "guard let", "??", "object?.property".

- There are some more, this is just from the top of my head.

EDIT: A better example of why Julia's syntax is less readable:

`images.first.resize(100, 100).crop(25, 25, 75, 75)`

versus

`crop(resize(first(images), 100, 100), 25, 25, 75, 75)`

Re:Julia as a CLI Calculator by peatmoss on Friday June 05, 2020 @09:47AM (#23428442)
> str.parse(Int).abs is more readable than abs(parse(Int, str)).

Oof, beauty is in the eye of the beholder. I appreciate the regularity of abs(parse(Int, str)) rather than remember what to call as a function, and what must be called as a method of some object. Of course my preference would be for a syntax that has the added benefit of getting rid of extraneous commas:

(abs (parse int str))

> 1-based indexing

Again, beauty is in the eye of the beholder. A lot of relevant math is 1-indexed. Also, I guess Julia supports arbitrary indexing, though I understand that defaults matter.

Re:Julia as a CLI Calculator by RivieraKid on Friday June 05, 2020 @10:33AM (#23428994)
> Oof, beauty is in the eye of the beholder.

I guess that's true, from my experience Julia's way is simply less readable. It also make IDE autocomplete much more useful.

> A lot of relevant math is 1-indexed.

Initially I kind of liked it and disagreed with people who didn't. But as I used Julia over time, I regularly encountered situations in which it was really frustrating and enacted a mental tax. The opposite never happens.

Re:Julia as a CLI Calculator by peatmoss on Friday June 05, 2020 @10:54AM (#23429247)
> But as I used Julia over time, I regularly encountered situations in which it was really frustrating and enacted a mental tax. The opposite never happens.

The opposite would be true for a large swath of people coming from scientific computing backgrounds if Julia defaulted to 0-based indexes. That said, in my experience people doing scientific computing have a poorly calibrated sense of what constitutes “hard.” I’m sure plenty of breakthroughs born of brilliant and horrifying code were created over sleepless weekends by grad students who didn’t understand that what they wanted to do was a mental tax.

I guess I don’t hear a lot of people doing scientific computing complain about indexing schemes. I prefer 1-based indexes, but 0-based indexes is a small and trivial issue in my list of grievances against, say, Python.

Re:Julia as a CLI Calculator by jessebett on Friday June 05, 2020 @02:17PM (#23431893)
I've encountered a few pieces of math that are more naturally expressed in 0-based indexes and it is pretty easy to define them in Julia using arbitrary indexing.

TaylorSeries.jl is a great example of this. x = x_0 + x_1 t + ... Then indexing into it with x[0] would give the zero-th order Taylor coefficient.

Re:Julia as a CLI Calculator by cbkeller on Friday June 05, 2020 @11:32AM (#23429690)
As someone coming from a physical science rather than CS background, I routinely find 0-based indexing to be "frustrating and a mental tax" compared to 1-based
Re:Julia as a CLI Calculator by sgt101 on Friday June 05, 2020 @09:51AM (#23428496)
>OOP support is "meh".

it's not an OO language. It's got a fantastically rich and powerful type system, but the true beauty of it is the way that it allows you to compose functionality. This is having a staggering impact on the evolution of the ecosystem and the progress that Julia libraries are making in creating functionality that now rivals code bases that have been in dev for 10+ years in the Python landscape.

>- str.parse(Int).abs is more readable than abs(parse(Int, str))

I respect your opinion, but mine is different. Perhaps other people find it easier to read asb(parse(Int,str)) as I do?

>- 1-based indexing.

You can change it and choose.

>- Lack of good support for nullability, think of "if let", "guard let", "??", "object?.property".

I don't know anything about this one! Fascinating!

Re:Julia as a CLI Calculator by RivieraKid on Friday June 05, 2020 @10:43AM (#23429109)
> You can change it and choose.

I know, not sure if it this would make things better or worse overall.

> I respect your opinion, but mine is different. Perhaps other people find it easier to read asb(parse(Int,str)) as I do?

I like when the code reads like a sentece, it's just less mental overhead.

Re:Julia as a CLI Calculator by ChrisRackauckas on Friday June 05, 2020 @10:48AM (#23429174)
Maybe you'd like str |> x->parse(Int,x) |> abs ?

>I like when the code reads like a sentece, it's just less mental overhead.

But the OOP version is further from a real sentence here. You're taking the absolute value of the string parsed as an integer, not "for the string grabbing the parser to apply the change to an integer to take the absolute value".

Re:Julia as a CLI Calculator by gavinray on Friday June 05, 2020 @11:08AM (#23429416)
I think they're both equally correct, though the UFCS/pipe syntax is mentally easier to follow.

Let's say someone told you (making up random stuff):

"The absolute value of the sum of the mean of the square of two vectors mapped over the product of X and Y."

Try to think about that in your head. By the time you've reached the end of the sentence, there have been so many steps and no context values that you can't even follow.

If you take the opposite though:

"Take the product of X and Y, map them over two vectors, square it, sum that, and then return the absolute value."

(Again, can't guarantee these are semantically equal to each other, but you get the idea)

Then you know "Okay, starting from these things, first I do this, then I do this.." whereas the opposite way, you're given a ton of directions with zero context, and then have to try to apply them all in reverse once you're finally given the starting value.

You don't give directions to someone starting from the destination and working backwards.

Re:Julia as a CLI Calculator by ChrisRackauckas on Friday June 05, 2020 @02:11PM (#23431805)
>"The absolute value of the sum of the mean of the square of two vectors mapped over the product of X and Y."

abs(sum(mean(abs2,x .* y)))?

Re:Julia as a CLI Calculator by johnhartigun on Friday June 05, 2020 @11:16AM (#23429498)
(Using a different account because I got a "you're posting too fast" error.)

It's probably even less readable to be honest. And it would mean there are now 2 ways of doing something which makes the language irregular (unless everyone switches to this syntax).

I would just read it as: "Take str, convert it to an int and take the absolute value." It also corresponds to the order of steps as it actually happens.

Another example where the readability difference is clearer:

`images.first.resize(100, 100).crop(25, 25, 75, 75)`

versus

`crop(resize(first(images), 100, 100), 25, 25, 75, 75)`

The former one isn't just more readable, it's also easier to write.

Re:Julia as a CLI Calculator by Xcelerate on Friday June 05, 2020 @11:12AM (#23429454)
> OOP support is "meh".

Interesting. I love Julia specifically because it doesn’t use an OOP approach. At least for the kind of work I do, I have found multiple dispatch to be far more powerful and cleaner to reason about than dispatching on the type of an implicit first argument.

Re:Julia as a CLI Calculator by leephillips on Friday June 05, 2020 @09:42AM (#23428397)
“OOP” is an anemic special case of the multiple dispatch that Julia provides. So if you don’t know any better you can program in that style using Julia.

“str.parse(Int).abs is more readable” No, but it makes sense if you also think that OOP makes sense.

You can index based on anything you want.

Re:Julia as a CLI Calculator by RivieraKid on Friday June 05, 2020 @10:57AM (#23429281)
No it's not. OOP is regularly used for new projects by experienced programmers. Julia doesn't have interfaces for example.

I know that I can set indexing to be 0-based. Not a good solution.

Re:Julia as a CLI Calculator by socialdemocrat on Friday June 05, 2020 @12:42PM (#23430494)
Most dynamic OOP languages don't have interfaces either, so that is kind of a poor argument. You cannot compare Julia to something like Java.

You got to compare it to Ruby, Python etc.

Also I have no idea what an interface definition would look like in Julia. A function in Julia isn't bound to one specific type like in an OOP language.

Re:Julia as a CLI Calculator by newen on Friday June 05, 2020 @03:16PM (#23432656)
I think interfaces in Julia might go something like

    interface AnimalActions
        function walk(x::Animal) end
        function call(x::Animal, y::Animal) end
        function eat(x::Animal, z::Food) end
    end
    
    struct Dog <: Animal
        name::String
    end
    
    AnimalActions.walk(x::Dog) = true
    AnimalActions.call(x::Dog, y::Animal) = true
    AnimalActions.eat(x::Dog, z::Food) = true
    
    setinterface Dog AnimalActions end
and then I guess using it like

    using AnimalActions
    d = Dog("rufus")
    walk(d)
Re:Julia as a CLI Calculator by dklend122 on Friday June 05, 2020 @05:24PM (#23434161)
The below package implements something like that, but better imo: https://tk3369.github.io/BinaryTraits.jl/dev/
Re:Julia as a CLI Calculator by cbkeller on Friday June 05, 2020 @11:43AM (#23429817)
Regardless of what is a subset of what, I certainly agree with the OP that OOP feels "anemic" in comparison to the dispatch-based paradigm of Julia.

I can't tell you how many times I've seen disparate packages written by different authors with no explicit effort towards interoperability "just work" together in Julia (e.g., [1]), something I have never seen to a comparable degree in any other language.

[1] https://www.youtube.com/watch?v=kc9HwsxE1OY

Re:Julia as a CLI Calculator by dnautics on Friday June 05, 2020 @12:30PM (#23430356)

    crop(resize(first(images), 100, 100), 25, 25, 75, 75)
this will likely get better when julia implements proper pipes, IIRC coming soon in the plans (like elixir does):

    images
    |> first
    |> resize(100,100)
    |> crop(25, 25, 75, 75)
If the language bothers to implement an inspect method (again, like elixir) this is vastly superior to . chaining because you can do this:

    images |> inspect
    |> first |> inspect
    |> resize(100,100) |> inspect
    |> crop(25, 25, 75, 75) |> inspect
trivially with multiline cursor (and also trivially ninja'd out with multiline cursor) and have full introspection on the evolution of your data through the pipeline. This is impossible in oo languages (well maybe you could do it in a prototyped language) because dispatch of the .inspect method would have to be implemented on each object.
Re:Julia as a CLI Calculator by jessebett on Friday June 05, 2020 @02:23PM (#23431970)
I'm not sure what `inspect` does, but can you clarify what you mean by proper pipes?

  julia> x = [3,2,4,5]
  4-element Array{Int64,1}:
   3
   2
   4
   5

  julia> x |> sort |> x->reshape(x,(2,2))
  2×2 Array{Int64,2}:
   2  4
   3  5
works.

It gives a syntax error if the pipes are on the newline. Is that your gripe?

Or is it that it doesn't automatically partially apply the function, requiring you to use an anonymous function, like `x->reshape(x,(2,2))` instead of as you have it `resize(100,100)` implicitly. I prefer the explicitness.

Re:Julia as a CLI Calculator by dnautics on Friday June 05, 2020 @04:47PM (#23433772)
Yes, by "proper pipes" I mean partial application. (I used to code julia but now I'm mostly living in elixir because that pays the bills) Yes, the explicitness of what you wrote is a marginal gain in preferability from an idealized point of view, but I promise you your eyes and brain will be more tired from that explcit form than if you just learn to read pipelines as passing into the first value (in elixirland we have lambdas that you can pipe into, too. Nobody does this.)

You don't know what you're missing by not having an inspect function. In elixir it's styled "IO.inspect", and it pretty-prints the value as a side-effect, and returns the value unchanged. You can pass a "label" option as your second parameter, and that will add a label to the pretty print. For example, assume I have a module M with the expected functions:

    value = 10
    |> M.add_3 |> IO.inspect(label: "A")
    |> M.times(4) |> IO.inspect(label: "B")
    |> M.minus_2 |> IO.inspect(label: "C")
will print:

    A: 13
    B: 52
    C: 50
and value will be assigned 50.

Now, the great thing about that is that you can blat a bunch of IO.inspects simultaneously using multiline cursors. That low friction 1) causes you to actually use it, and 2) cause you to also set your code up so that it's easy to IO.inspect, which typically also means cleaner, and easier to read code. It is IMO the most powerful debugging tool that I've ever used.

Example: https://github.com/ityonemo/ex_dhcp/blob/master/lib/ex_dhcp....

That small pipeline does a pretty complex set of actions - deserialize a raw binary to a structured datatype, then call a handler, then process a handler return result. There are four datatypes that run through that pipeline. Nonetheless, I can inject IO.inspects into that with six keystrokes (I have a vscode snippet), run the code, and watch as the data are transformed, and immediately identify what corner case I missed and write a proper test for it.

And yes, it is far less powerful if the pipes can't tolerate the newline. (though you usually can still multicursor on a single line).

Anyways, I'm not saying this to rag on Julia. I'm just saying I think julia can and SHOULD have this, and it would be awesome. Also, elixir needs to learn a thing or two from julia's repl.

Re:Julia as a CLI Calculator by mcabbott on Friday June 05, 2020 @03:19PM (#23432695)
You can do this:

    @_ images |> filter(size(_,1)>100, __) .|>
    resize(__, 100,100) .|>
    crop(__, 25,25,75,75)
with Underscores.jl. Not exactly `images.first.resize(100, 100).crop(25, 25, 75, 75)` anymore, to point out that this doesn't need every function to prioritise one argument, the pipe feeds into __ in any position. And that .|> applies them to each element.
Re:Julia as a CLI Calculator by RivieraKid on Friday June 05, 2020 @03:08PM (#23432556)
> This is impossible in oo languages

It's possible in languages which support extensions, such as Swift, Dart or Kotlin.

Re:Julia as a CLI Calculator by dnautics on Friday June 05, 2020 @04:48PM (#23433781)
no it's not, because a key part of OO is encapsulation. You really do need a functional language with naked, fully introspectable types everywhere, for this to work effectively.
Re:Julia as a CLI Calculator by RivieraKid on Friday June 05, 2020 @06:20PM (#23434693)
I tried it in Dart and it worked, so it's possible.

But maybe I don't understand your point, if so, tell me what exactly would be impossible to implement in a language like Swift, Dart, Kotlin.

Re:Julia as a CLI Calculator by dnautics on Saturday June 06, 2020 @02:14PM (#23441166)
yes, you can add an inspect method to every object, but you'll also have to add an inspect method to every object. That's the problem.
Re:Julia as a CLI Calculator by dunefox on Friday June 05, 2020 @09:43AM (#23428412)
> - OOP support is "meh".

And boy, am I ever glad it is.

Re:Julia as a CLI Calculator by sgt101 on Friday June 05, 2020 @09:51AM (#23428502)
Having built several OO codebases with 1000+ classes I really really really second this view.
Re:Julia as a CLI Calculator by cbkeller on Friday June 05, 2020 @11:10AM (#23429432)
OOP has become an antipattern (ok, partially kidding but...)
Re:Julia as a CLI Calculator by sgt101 on Tuesday June 09, 2020 @05:35PM (#23471164)
There are a few scenarios in which I miss simple inheritance when I write Julia code, they are few and far between (in real world problems). What fascinates me is how virtually the whole of the programming world decided that inheritance was the way to go and pursued it for 20 years - on the basis of what now looks like zero evidence.
Re:Julia as a CLI Calculator by cbkeller on Tuesday June 23, 2020 @03:26AM (#23610844)
Yeah, absolutely
Re:Julia as a CLI Calculator by stellalo on Friday June 05, 2020 @12:18PM (#23430230)
> OOP support is “meh”

But multiple dispatch support is great!

Re:Julia as a CLI Calculator by socialdemocrat on Friday June 05, 2020 @12:37PM (#23430438)
I used to be a big Swift fan but as I go back and forth I must say Julia is a much better language, and a lot of that is down to syntax.

Swift syntax is really a pain to deal with. I programmed Objective-C for many years, and that syntax makes sense for object-oriented programming. But it is a disaster for functional programming.

Making closures and calling function objects gets really confusing with Swift syntax. Swift methods cannot naturally be passed around like a Julia function.

> str.parse(Int).abs is more readable than abs(parse(Int, str))

The problem is that the Swift approach entirely lacks composability. Julia's `abs` and `parse` can easily be passed around as first class objects. Besides a lot this readability cases can be solved with the `|>` operator like this:

parse(Int, "-12") |> abs

The Julia approach makes it easy to use functions as arguments to higher order functions such as map and broadcast. Using dot (.) is shorthand for broadcast which lets you do stuff like:

abs.(parse.(Int, ["-12", "-3"])) parse.(Int, ["-12", "-3"]) .|> abs

Both cases show parsing an array of numbers and taking the absolute value.

> 1-based indexing.

I know many people hate this but I don't get it. I have spent most of my life with 0-based indexing yet this represents no obstacle for me. When I use Julia I just think as if I am writing math. All my math text books are 1-indexed based and that is just something you get used to. In fact after using Julia for a long time, I frankly prefer 1-based indexing.

0-based indexing IMHO is quite nice when you are dealign with inserting numbers into arrays, or with C-style loops. But neither is usually done in Julia.

> Lack of good support for nullability, think of "if let", "guard let", "??", "object?.property".

That used to bother me as well coming from Swift. But this request actually makes not sense in a dynamic language. What you are basically asking it to have programming constructs to give you type safety at compile time. But Julia is a dynamically typed language, so you will never have this anyway. It if a fools errand.

Julia is built to catch type problems at runtime, not at compile time. Those problems will be caught at runtime in Julia even without `if let` and `guard let`. They don't actually add any value to a language like Julia.

Swift NEEDS these constructs because statically typed languages are quite poor at catching type problems at runtime. They are very dependent on catching type problems at compile time.

> OOP support is "meh". I kind of view that as a positive. I have spent years doing object-oriented programming but I must say the Julia way just makes a lot more sense. It is so much easier to work with. I find OOP inherently bad for a REPL environment. And REPL environments make me a lot more productive. You can built up functionality in a far more incremental and iterative fashion.

I still quite like Swift, but I feel it is going in the wrong direction. I tell tale sign for me when going back to Swift code these days is being reminded just how complex the language and the tools have gotten. If you do Swift everyday, that is easy to forget, but the whole toolchain is actually kind of complex.

For instance getting a closure setup correctly with appropriate tagging for life time/ownership of data is not easy. The Schizophrenia between trying to be both an object-oriented language and a functional one becomes more and more apparent.

Sometimes I wonder if Apple made the right choice and whether going with something more akin to Objective-Smalltalk would have been better. It would have been a more natural fit with the Objective-C syntax, which feels very wrong in a functional setting.