Indeed it is! The standard IBM punch card had 80 columns.
> and not 100
The standard IBM printer models had 120 print positions.
The Venn diagram of Fortran feature availability in the various actively maintained Fortran compilers is very messy, and the ISO standard is definitely not a subset of any of them. Standard-conforming code is not necessarily portable, and highly portable code is not necessarily standard-conforming, especially since Fortran '95.
X .= f.(2 .* X.^2 .+ 6 .* X.^3 .- sqrt.(X))julia> X = [1.,2.,3.]; f=sin;
julia> @. X = f(2 * X^2 + 6 * X^3 - sqrt(X))
c_y = (qmr*ey_sub*dtsq + c_y*(2 - omsq_b*dtsq))/gmdto2p1 - c_ym1*gminv
ey_sub, c_y, c_ym1 are N long arrays with the same shape, and in this case, the operation is elementwise, so indexing isn't needed, and I do not need an explicit do-loop (for loop in C languages) so it fits on a single line that is readable to a scientist in the field. The julia equivalent, I think is the same with a period on every operator c_y .= (qmr.*ey_sub.*dtsq .+ c_y.*(2 .- omsq_b.*dtsq))./gmdto2p1 .- c_ym1.*gminv
The assignment was already verbose as it is, and I at the time tried to make it terser but still marginally readable by using variables that are named for...scientists I guess (e.g., gmdto2p1 means "gamma * dt / 2 + 1" dto2 thoughout the codes I read and use is "dt over 2") and adding 10 characters makes a little more cumbersome. While I think the visuals can be acclimated to, it is tedious to write, especially when you translate a formula from vectorised form to non vectorised or vice-versa and have to insert or delete periods. Mind you this is one of the simpler formulae in the code in question. You can imagine it quickly gets worse when the number of terms exceeds 6 or so.If you can't rely on implicit-do or terse assignment statements, then the good alternative in terms of readability then for the formula is just to do an explicit do-loop (for loop for julia).
! fortran 90, `integer i` above
do i=1,size(c_y)
c_y(i) = (qmr*ey_sub(i)*dtsq + c_y(i)*(2 - omsq_b*dtsq))/gmdto2p1 - c_ym1(i)*gminv
end do
# julia
for i=1:length(c_y)
c_y[i] = (qmr*ey_sub[i]*dtsq + c_y[i]*(2 - omsq_b*dtsq))/gmdto2p1 - c_ym1[i]*gminv
end
The problem is then I have made more extraneous bits to worry about. This gets even more hard to parse when the shape of the arrays exceeds more than 3 dimensions. I've read C style codes that are 7 levels deep with different indices, god is it painfully unclear and easy to get lost reading that, it's best to hide extraneous loops with syntactical sugar where possible such as to keep the algorithm as clear as possible, especially when it's a simple elementwise operation. It isn't like you can hide complexity all the time (or that it's even a good idea to do so), but this was a code for just two figures in a paper that needed a bit more oomf than numpy could, so given the time constraint for me, the size of the problem and everything, fortran fit much better.If you want to know more about the dot macro in julia, here is a nice blogpost about them[0]. The line above is from work I did for a paper that I initially thought "hey, it's been a few years, why not see if julia has stabilised by now" only to find out this was a decisive change they made. I mean they might deserve praise having made this macro a very general thing and apply widely to things that aren't just syntactical sugar for broadcasting, but after being frustrated trying to write my code, googling, and then finding this post, I basically dropped the julia learning effort and got the code written in fortran and made my figures. I can learn things in my spare time to a limit but at the end of the day I have a job to do.
I still want to give julia a chance because the idea does seem cool. I complain about computer scientists a little tongue-in-cheek but really I find the metaprogramming in julia pretty interesting. I'm just not sure I can use it in my day job as a scientist without some effort in learning and time on my part which is at a premium right now.
A useful macro is @. which allows you to write "@. A * B * C" instead of "A .* B .* C". Also the macro avoid the creation of an intermediate vector with A times B.
I've certainly had moments where I've gone "just do that elementwise already, it's obvious!" and been mildly annoyed, but I'll take that any day over silent misbehaviour, hard to detect bugs, and being unable to tell at a glance what exact operations are going on in a line of code.
Functions like exp and sin can be defined on numbers, but are also well defined on square matrices. In languages that have automatic broadcasting of functions across arrays, if you write exp(x) and x happens to be a matrix, you won't get the mathematically correct answer. You actually get [exp(xi) for xi in x] which is nonsense.
Having the dot operators make it very easy to tell if a function should be operating on entire arrays or on elements of those arrays. It also enables performance enhancements, because if I write
exp.(x) .+ 1
that will do [exp(xi) + 1 for xi in x] instead of [y + 1 for y in [exp(xi) for xi in x]] which wastes and allocation