Julia included in Oreilly's "Emerging Programming Languages" report (June 2019)

It’s a nice and positive presentation of the language, although superficial compered to the others they covered:

8 Likes

Julia is an enormous language

You reckon this is true? It seems kind medium-sized to me–though I have to admit, the apparent eagerness of the core devs to add syntax is the only significant source of trepidation I have about the language. I don’t feel like it’s enormous yet, but it does seem like it could get that way if a more restrained approach to adding features isn’t taken in the future.

3 Likes

I am not quite sure what you mean here, can you give a few examples? I feel kind of the opposite: extra syntax is usually added after careful consideration. Eg #24990.

11 Likes

I think it’s just perspective. Someone who doesn’t do technical programming for a living looks at Julia and goes "man, they have a lot of weird extra syntax for math people like \, mul! vs *, @., Tridiagonal, etc., while omitting the things people are used to seeing in a basic language implementation like a web server (yup, quite a few languages have on in there) or graphics engine (usually much bigger than the entirety of Julia). But when you see something you don’t expect, you go “they add a lot of peculiar things”.

4 Likes

It is possible that I understand syntax in the narrow technical sense (syntax is what the parser eats).

For me Tridiagonal, mul!, and * are not syntax; @. is. :wink:

1 Like

Probably one example at I wrote a guide about Object Orientation and Polymorphism in Julia. opinions wanted! - #48 by ninjaaron

I understand * and \ as syntax, but not the rest, they are just names. Actually, even those are just operators, not sure if they count as syntax. The @ itself is syntax.

The goal of this report seems ambitious but IMO it does not have enough details for any language. I think it needs to go just a little bit deeper to be useful. I’m pleased to see Julia gets covered though.

3 Likes

Well, it’s encouraging to see that they are being careful about it. It would be more encouraging to see some examples of extra syntax being rejected after careful consideration–though not necessarily this specific case. I’m biased towards anything that helps with pipelines.

For me, the canonical example is the for loops. for x in xs vs. for x ∈ xs vs. for x=xs. I realize that the the first two are alternate ways to write the in operator (because every languages needs two of those, right?), but the for x=xs definitely qualifies as additional syntax.

Then you’ve got comprehensions syntax vs. the usual functors (map, filter and friends) vs. dot broadcasting. I like all of those things, but they are all sight variations on the same concept.

import vs. using

Splatting with ... vs. array concatination with ;. I realize these are quite different… but then they are kind of the same when defining a new array, only you’re supposed to use ; if it’s an array you’re “splatting” into your new array, but not necessarily a lazy iterable. I do admit that I find the syntax for array literals in general to be a bit overwhelming, but I suspect that is because I never use multi-dimensional arrays, and I assume the extra syntax is necessary for those who do, so that’s not one of the ones that bugs me.

Yes, and that’s the latest one I’ve discovered. Another related one which no one has been able to explain to me is the difference between Array{T,1} where T and Array{T,1} where {T}. If they are the same, why are they both supported? (I don’t know if they are the same, but nobody knew a difference when I asked)

I will say that generics in gnereal are one area where Julia definitely hits the jackpot in terms of giving a lot of expressiveness with very little syntax.

I give all explicitely marked macros a pass. @ is syntax, but every little micro DSL I just file away under that single feature. Places where the languages transforms something with macros implicitly, that’s syntax. I’m actually very pleased that most of Julia’s concurrency features are wrapped up in explicit macros rather than new keywords, since you can see how all of it works with @macroexpand.

Of these features, \ is the only one I find a little unnecessary, but I’m generally willing to ignore “math stuff” I don’t use because I assume it’s there for a reasons and I never really have to deal with it. The thing I might object to a wee tiny bit is all the functions that have some alias to a unicode operator, but I try to suspend my misgivings about this because I can imagine its helpful to be able to express oneself in code the same way one would in a paper–on the other hand, I know a physicist who does technical computing for a living and is much harder on Julia’s novel math syntax than I am, but I’ll leave that discussion to the domain experts.

In the end, It’s not any one bit of syntactic sugar that’s too much, it’s just the number of cases where there are multiple ways to the same or nearly the same thing reminds me a bit of Perl. I don’t think Julia is an enormous language… I just… don’t want it too be one, either!

It was more just when I read this sentence in the report that I was like, “oh, maybe I’m not just paranoid.”

They are probably including macros or something, or maybe all the functions in the default namespace (which is admittedly way more than most languages, but that doesn’t bother me. A function is a function.)

3 Likes

They are the same. However the second one is more compact when writing of more complex types, for example SArray{S, T, L} where S where T where L can be shortened to SArray{S, T, L} where {S, T, L}

2 Likes

I do feel the same.

I think the difference is clear once you know it:

  • using M if you want all symbols exported from M
  • import M if you only want M to be in your namespace
  • using M: f, g if you only want to call functions
  • import M: f, g if you want to extend functions (without fully qualifying them like M.f)

FYI you can also expand native syntaxes using Meta.@lower. For example,

julia> Meta.@lower x[y] .= f.(z)
:($(Expr(:thunk, CodeInfo(
1 ─ %1 = (Base.dotview)(x, y)
│   %2 = (Base.broadcasted)(f, z)
│   %3 = (Base.materialize!)(%1, %2)
└──      return %3
))))

Once I realized that many syntax magics happen at lowering phase, it felt like Julia is more minimalistic (compared to the impression before realizing it).

4 Likes

It shortens to SArray{S, T, L} where {L, T, S}.

It is still equivalent which is my point.

julia> (SArray{S,T,L} where {S, T ,L}) == (SArray{S,T,L} where {L, T, S})
true

Equivalent in some context (where the order of S,T,L does not matter), different in other (where their order does matter).

SArray{S, T, L} where {S, T, L} is the same as SArray{S, T, L} where L where T where S.

While for printing, === or directly observing the fields they are different but from a type standpoint in Julia they are the same.

julia> (SArray{S,T,L} where {S <: Int, T <: Real ,L <: Complex})  <: (SArray{S,T,L} where {L <: Complex, T <: Real, S <: Int})
true

julia> (SArray{S,T,L} where {L <: Complex, T <: Real, S <: Int}) <: (SArray{S,T,L} where {S <: Int, T <: Real ,L <: Complex})
true

julia> (SArray{S,T,L} where {L <: Complex, T <: Real, S <: Int}) == (SArray{S,T,L} where {S <: Int, T <: Real ,L <: Complex})
true

If Julia took order into account while determining specificity in type dispatch, like Common Lisp, it may have mattered that the expression after the where was in a different order but Julia does not.

Are you following discussions here, and issues and PRs on Github? At this stage of the language, many (I would say most) proposals for syntax changes are actually rejected.

Not really. They have an intersection, but they are different. Both have their uses (and similarly list comprehensions).

I hope you realize that ... has uses outside creating arrays — in fact, it has nothing to do with arrays per se.

Your point about = and in in loops is valid. @tkf has explained the difference between import and using.

While Julia is of course not perfect, I am wondering if your impression about the “eagerness to add syntax” stems from a superficial understanding of some elements of the language.

3 Likes

As far as I can tell (despite some syntax examples) you seem to be more concerned about the number of names defined in Base than actual syntax.

The good news on that front is that there has been a concerted effort to slim down Base, and move things out. So much so, that I frequently see people clamoring to bring things back or put new stuff in.

(I totally agree on for i = ..., btw. I really dislike that particular Matlabism.)

5 Likes

I looked it up recently, so these differences are still in my mind, I just don’t get why there needs to be two keywords for this. I personally would rather have fewer semantic options. i.e. one option for all exported symbols (not extensible) and one for importing just the module name. Module.function aways required for extension.

This is very cool, thanks!

Good to know, thanks!

I’m glad to hear it. It seems like most of the proposals I end up hearing about get through, but, as you say, I don’t follow the all the proposal requests closely. It’s probably mostly the ones that have some support from the core devs that trickle down to me.

yes.

I guess it’s possible. From my perspective–which may be skewed, as you point out–I just see a lot of syntax for similar kinds of things. I realize that dot broadcasting, map’n’filter and comprehensions are different (well, comprehensions are basically same as Base.Filter + Base.Generator, but broadcasting is a little different), but with subtly different semantics.

I tend to gravitate towards languages that are intentional about restricting themselves to a smaller number of syntactic forms, and I’m not sure Julia is that kind of language. I do realize that most syntax features are just sugar for normal functions and macros, but that doesn’t make them… not syntax.

What gives you that impression? I find it convenient to have a lot of stuff in Base. I hope they at least leave the functions for dealing with files and the filesystem in! That’s (maybe) my favorite thing about Julia! I also like having easy access the the functions for running and communicating with external processes, though I could understand if that were moved out of Base. (but I guess it won’t be, since there is literal syntax for commands in the language, and it would be silly to have to import a bunch of functions to be able to use this language feature.)

I think the main problem with the current situation is not that map, broadcasting, and list comprehensions are too similar (and thus redundant syntax for the same thing), but that they are quite different, and a new user may have a difficult time understanding the difference and, more importantly, picking when to use the right one. Pitfalls like

julia> map(+, 1, 1:3)
1-element Array{Int64,1}:
 2

julia> 1 .+ (1:3)
2:4

can be surprising since eg map in particular can’t be accused of being overdocumented. I would of course make a PR but I am not sure I know all the corner cases. The differences are scattered in comments like these.

6 Likes

Your position is a curious mixture of being a purist when it comes to language design (avoiding constructs you consider redundant) and a kitchen sink approach for “built-in” functions. :wink:

People may find it convenient to have stuff in Base, but at the same inconvenient to develop stuff in Base, or even the standard librares. As long as their release cycle and versioning is coupled to Base, changes are going to be very slow (2-3 times a year, compared to packages which can get new features with a complete deprecation cycle in a matter of weeks), and consequently people tend to be more conservative about what goes into Base and the standard libraries.

I wonder if people arguing for “batteries included” realize that this means that they get stuck with one battery type for longer time, when with a more modular approach they would already have the shiny new batteries with 2x the capacity, a mascot playing a percussion instrument, and a raygun (* while stocks last).

9 Likes