Out of curiosity, what was the bug you ended up with with the integer instead of floating point array? Are you suggesting that integers should not exist at all in this Julia light?
Kristoffer, Again, I am not suggesting modifying Julia, but (perhaps for a Wrapper?) just as an integer variable changes to float when multiplied by a float (I think it does, anyway?), if an integer variable is assigned equal to a float, might it not change type also?
I really, honestly, cannot see that. At worst some are implying that you are inexperienced with Julia, but is that wrong?
I do think it is a somewhat important point, though. Could you explain what you think should happen when you multiply two integers? In Matlab literal numbers are always floats. Is that what you are looking for?
But that’s what it already does. Or do I misunderstand?
julia> x = 2.0
2.0
julia> x = 2
2
julia> typeof(x)
Int64
Not as part of an array
If you have an integer array, and assign a float to one of the elements, promote the entire array to float? And vice versa with integers to a float array?
I would like a package to go further in trying to figure out what the user wanted…
In general, Julia tries not to guess what the user wanted when it’s not entirely clear. Because guessing is going to be wrong a lot of the time and it’s better to throw an error and require the user to be explicit about what they meant. A lot of dynamic languages have taken the opposite approach in the past. For everything the user could possibly write, they’ve given it a meaning, which, in ambiguous situations is an inherently arbitrary choice. The premise is that this is more convenient, but it often leads to situations where programs appear to be working but are silently doing something very wrong. For example, R has traditionally “recycled” arrays if they don’t have matching lengths, so this would work:
> a = c(1, 2, 3)
> b = c(3, 2)
> a + b
[1] 4 4 6
Warning message:
In a + b : longer object length is not a multiple of shorter object length
Sure, maybe sometimes you actually want to start using values from the front of the array but usually that is not what you want and if that’s happening in a program, it’s a bug. This was so dangerous that R recently made it a warning. But this is a perfect example of why this kind of “well, it might as well do something” attitude is dangerous.
Fun game: How to write R’s recylcing behavior in Julia? I can think of two very different ways to do it.
[a[i] + b[mod1(i, end)] for i=1:length(a)]
map(+, a, Iterators.cycle(b))
like my example above… if I am setting an array equal to a float, then it generally means I want it to be a float.
Can you provide some example code to show what happened? Do you mean that you created an integer array and then assigned a floating-point value into it?
If I add a constant to an Array and leave out a ‘.’, everything shouldn’t fall over.
Ok, so you want this to work:
julia> A = rand(3, 3)
3×3 Array{Float64,2}:
0.556981 0.689973 0.940542
0.820641 0.135636 0.963501
0.981247 0.0442999 0.235078
julia> A + 1
ERROR: MethodError: no method matching +(::Array{Float64,2}, ::Int64)
Fair enough. Let’s simulate that for the moment:
julia> Base.:+(a::AbstractArray, x::Number) = a .+ x
julia> A + 1
3×3 Array{Float64,2}:
1.55698 1.68997 1.94054
1.82064 1.13564 1.9635
1.98125 1.0443 1.23508
How cool is it that this is so easy to do?! That one definition immediately makes this work for all kinds of arrays. Now how about this:
julia> using LinearAlgebra
julia> A + I + 1
3×3 Array{Float64,2}:
2.55698 1.68997 1.94054
1.82064 2.13564 1.9635
1.98125 1.0443 2.23508
julia> (A + I) + 1
3×3 Array{Float64,2}:
2.55698 1.68997 1.94054
1.82064 2.13564 1.9635
1.98125 1.0443 2.23508
julia> A + (I + 1)
3×3 Array{Float64,2}:
2.55698 2.68997 2.94054
2.82064 2.13564 2.9635
2.98125 2.0443 2.23508
Oops. We broke the associativity of +
. And not in the slight way that it’s already broken for floating-point numbers—we really broke it.
That’s why A + 1
doesn’t work. Not because we wanted to be annoying or pedantic (and certainly not to be user-unfriendly). There were a few versions of Julia pre-1.0 where A + 1
did work until someone realized that we’d broken the associativity of +
and we had a long discussion about what to do. The conclusion was: breaking associativity is pretty bad and A + 1
is kind of questionable from a mathematical perspective (you can’t add matrices and scalars), so we should probably be a little more careful about this and require people to explicitly indicate whether they want broadcasting or not.
The whole mutability issue is beyond the needs of most users,
Seems simple to advise beginners to use mutable struct
and not worry about it.
the local/global as well…
If you’re talking about this issue, then yes, that was annoying, but it has now been addressed. On Julia master, this works:
julia> s = 0
0
julia> for i = 1:10
s += i
end
julia> s
55
In a file this will produce a warning and tell you to write global s
in the loop (or use local s
if that’s actually what you meant). You can read about the rules and why it works the way it does in the latest version of the manual.
I could go on…(if you are interested)
I am interested, since there are always things to be improved, although I suspect based on the above that most of these things have probably been thought about and debated long and hard and the choices that have been made were made for legitimate, if not immediately obvious, reasons. It also feels like some of this stems from being accustomed to other systems that are no easier to use, just more familiar.
I am not suggesting a ‘split’ but potentially a Wrapper, like Keras for TensorFlow, or LateX for TeX, (and maybe in a way R-Studio for R). These did not split, but greatly enhanced user experience (and increased user-base).
This is something that Julia does not do for performance (and I like it), but causes some problems in code where you don’t know the types beforehand. Let me make you an array type that does what I think you want. (basically define a setindex!
that widens the array type on demand.)
I encountered the same problem when working on tensor hessian of implace functions, as the caches are of type ForwardDiff.Dual
that are created by ForwardDiff, not me. I will publish a solution for that soon
In the case of broken associativity above, yeah, sure there is an ambiguity, but in cases of no ambiguity why couldn’t it just work?
How would that work? How does one know if there’s an ambiguity or not?
If there are only 2 terms being added, then there is no ambiguity
Is this related to Broadcasting UniformScaling Operations · Issue #23197 · JuliaLang/julia · GitHub? By which I mean, could I
broadcast like a diagonal matrix to restore associativity with this +
method?
I just mean that if the parentheses were there, there woudl be no ambiguity, or if a constant were being added to s single Array, then there wouldn’t even be any issue.
Concerning (La)TeX; I’ve been using it far longer than Julia, almost a quarter of a century ( ), and I love it, and it is beautiful. But I also hate it, and it’s terrible. It is extremely user-unfriendly.
Compared to LaTeX, Julia is superfriendly.
And you like plain tex better??!!!
No! But if you can call LaTeX user-friendly, and require students to use it, then I suggest to give Julia a bit more time.
There are only two terms in each addition operation in both of the parenthesized forms. It would potentially be possible to make the unparenthesized form A + I + 1
an error, but that is very brittle. The issue is not the parentheses, it’s the fact that doing the addition operations in different orders produces different results. There’s no getting around that with syntax games.
A+1 is unambiguous, at least.Why can’t that work?
With regard to your idea about having an error without parentheses, that seems intuitive and sensible (IMO), I don’t know what you mean by ‘brittle’.
Actually, A + 1
is often interpreted to mean ‘add one to the diagonal of A
’
I’m not mathematician but it feels like adding apples to oranges for me.