I have always been skeptical about 'scientific' languages. Why do you need a special language when any general language + some libraries will do? This is a good example of a feature that only really makes sense in a scientific language.
Numerical programming takes more expressive power than one might imagine. In most languages, numerical primitives like integers and floating-point numbers, and numerical operators like `+` and `[]` (array indexing), are very special and are endowed with enough magic to be usable. E.g. in C, `+` is too polymorphic to be defined as a function; in Python, `+` has special `__radd__` methods to (hackily) emulate multiple dispatch; in Java `int`, `float` and `double` are entirely different kinds of values (non-objects) from normal user-definable objects. In many ways, the fundamental premise of Julia is to design a language with sufficient power and performance that numbers are not special: "primitive" types like `Int`, `Float64` are just defined in normal Julia code, and operators like `+` and `[]` are normal Julia functions like any other.
Julia is my language of choice for writing compilers.
Quasiquoting means that codegen is as easy as string interpolation is in other languages.
quote
let
$(index_inits...)
$(results_inits...)
if $(reduce((a,b) -> :($a && $b), true, index_checks))
let
$(var_inits...) # declare vars local in here so they can't shadow relation names
$body
end
end
tuple($(results...))
end
end
Great introspection into the inference and compilation pipeline, directly from the repl.
It catches type errors early, thanks to the typed multiple dispatch.
julia> xs = []
0-element Array{Any,1}
julia> push!(xs, 42)
1-element Array{Any,1}:
42
julia> push!(xs, "foo")
2-element Array{Any,1}:
42
"foo"
julia> ys = Int64[]
0-element Array{Int64,1}
julia> push!(ys, 42)
1-element Array{Int64,1}:
42
julia> push!(ys, "foo")
ERROR: MethodError: `convert` has no method matching convert(::Type{Int64}, ::ASCIIString)
This may have arisen from a call to the constructor Int64(...),
since type constructors fall back to convert methods.
Closest candidates are:
call{T}(::Type{T}, ::Any)
convert(::Type{Int64}, ::Int8)
convert(::Type{Int64}, ::UInt8)
...
in push! at ./array.jl:432
Plus, I only have to think in one language, but I can write sloppy dynamic heap-allocating-everywhere code in the compiler and with just a bit of thinking emit zero-allocation statically-dispatched code in the output.
I would say there's something magical about the way that Julia is structured that makes it more than just a scientific language. I wrote a DSL for Julia for writing clean combinatorial verilog (haven't tackled sequential yet) in 3 days, using lispish macros. It took another 1 day to hook it up to 'verilator' which transpiles the verilog to C and lets you crosscheck it by loading it back up in Julia.
This is very important if you're planning to build hardware to do specific math - because Julia is incredibly good at mathematical modeling, and you can very rapidly set up comprehensive tests for your hardware designs with confidence.
The closest alternative is chisel, which is written in scala. Although it's more professionally maintained and more fully-featured, it's hard to call the verilog chisel emits "human-readable", and it's harder to set up comprehensive tests - berkeley hardfloat, which is a very impressive project in chisel, had several critical bugs in its implementation (that I found, using julia).
That's really nice. Now we need VHDL.jl as well - maybe different HDL backends could be bolted on? Julia is much better suited for this than Scala due to Julia's macro system.
I'm not sure if "special language" is a particularly apt description of what Julia is. SQL is a "special" language.
At any rate - a lisp-like language with llvm backend, package manager, and a (small, but not trivial) group of users writing real software - what's not to like?
I (still) recommend the talk: "Julia - to lisp or not to lisp?", that gives a quick overview of some of the design choices:
For me, I like that it has a real story trying to balance "actual integer math" (not this silly machine constrained twos-compliment hack" and "you could conceivably write a ray tracer that wasn't unusably slow" :)
As a scientist, it's nice to have an option where I can easily espress my problem, and get a speedy solution at the end. Julia hits this sweet spot.
I translated some of my code from one of those general purpose languages to Julia 0.2, years ago. It was both more readable, and 20x faster. Never looked back.
In R, I can import a CSV, plot a histogram of each column, and fit a linear regression of one column against the others in about 5 minutes and 15 lines of code.
In Python, I can do the same thing if I install the Pandas and Statsmodels libraries first.
Try that in Ruby, Perl, C++, C, Java, Rust, Haskell, Common Lisp, or just about any language you can think of. Good luck.
It's easy to forget that R inhabits a gray area between a full-fledged programming language and a "statistics package" like SAS or SPSS or Stata or GRETL.
Languages like Julia, R and Matlab offer a whole lot in the way of built-in syntax, data structures, functions and constants for scientific computing that you would have to get from libraries in general purpose languages. But unless those languages have the kind of libraries that Python offers, such as Numpy and Pandas, you're not going to have that kind of support.
In addition, scientific languages will have libraries mostly in that domain. You can't beat R's library when it comes to statistics. They will also have good plotting libraries.
What you also get with Julia and Fortran is code designed to be optimized for numerical computing. Python attempts to offer this kind of performance via Numpy, which is Python wrapper on C or Fortran BLAS library. Or by JIT compiling with Numba, which is something Julia does automatically the first time you call a function.
One of the big wins is being REPL/workbook-focused, rather than REPL/workbook as an afterthought.
When I'm building software, I tend to like things to have very tight interfaces -- box everything up into components, understand how they talk to each other, etc. Define interfaces, implementations, types, etc -- In general, optimizing for long-term maintainability.
When I'm exploring data, my thought process is much more "scatter everything about on the desk" and "let me run these 5 lines of code again within the current context". "What does this thing look like", etc. Having "a table of data" as a first-class citizen in the language, with all the libraries assuming that as input and everything optimized to work around / display / visualize such is incredibly useful.
I've done mathematical programming in both C++ and MATLAB. As much as I hate MATLAB as a language, it's way faster and easier to prototype things. There's a huge library of vetted functions for scientific things I'm interested in, and having matrices built into the language is great. MATLAB has tons of warts though, so I'm looking forward to switching to Julia this summer.
One of the biggest warts is the casual elision of vectors and nx1 matrices... (and scalars and 1-arrays and 1x1-matrices). Julia wrestled with this in its early days, but I think the way it does things now is quite nice.
Python Panda default to Null and before that it uses something else to represent missing data. Null value in general is the last thing you do when you don't know how to represent a certain type. If you have a type language with sum type and pattern matching then you don't even need null. And yes R have its own Null type so NA is separate from it.
Erlang have PID as a primitive.
I think any domain specific languages are smaller in rules and syntax, and it makes it very very easy to learn for experts and people of those domains.