By soon I don’t mean when the feature might arrive, I was talking about the const check occuring long before a function call, which would have to be Julia’s parse time.
Python is one of the biggest languages out there now and it doesn’t have this kind of const. The Final you mentioned earlier is a feature of mypy, and it’s more like Julia’s const than C++'s const because Python variables are very similar to Julia variables in design. There are many reasons people elect not to use Julia more, and while I’ve heard about insufficient compilation saving on a regular basis, this is the first time I’ve heard about consting mutable instances via a variable. It’s fine to use statically typed languages like C++ (maybe Rust is a better analog because it’s also based on LLVM) and their features to develop large projects, but I really don’t see other people demanding such features from a dynamically typed language like Julia. It’s a contradictory demand like wanting a heavy sprinting bird to also fly well.
I’m pretty certain that the near-consensus here was that Julia can’t support this particular feature, though a linter could do other useful static analyses at parse-time, like recognizing the x/x! typo earlier.
And when we say can’t we mean provably it’s impossible it’s equally hard as solving the general halting problem in fact it can be converted into a halting problem.
It’s easy to construct ridiculous examples that illustrate this for example create a function which reads continuously from the cryptographic random number generator on the operating system and if it encounters the text of Romeo and Juliet it writes out a Julia expression that creates a method for a function which mutates its arguments which is a function that you’re const method calls.
People want the dynamic capacity and that’s what Julia is about this dynamism hence mathematically we can show the problem of determining constness is unsolvable QED
f(mut a, b) has the b constant. You don’t need any fancy examples or tools to determin it.
The only minor change to current Julia is to treat as different functions f(mut a, b) and f(a, b).
We are amasing at thinking complicate even when the problem is obvious.
This is not clear to me, still, and I’m wondering if you are referring to mutability of values (which you can have in Julia) or mutability of variables (which you can’t).
So, if I define
f(mut a::Vector) = ...
f(a::Vector) = ...
and then I call f([1, 2, 3]), which version of f should be invoked?
I explained before how is done in C++ because I’m more familiar with it. It is called function overloading resolution or yet another level of static or compile time polymorphism. Operator overloading lhs and rhs in C++ is done like this for example:
When addressing the elements of a vector in const manner (rhs) or a = v[i] it uses the constat version of it and in the v[i] = a it uses lhs version. So even the operator has two different implementations. Same with any other call in C++ void f(int&) is not the same with void f(const int&).
struct T
{
value_t& operator[](std::size_t idx) { return mVector[idx]; } //lhs or mutable one.
const value_t& operator[](std::size_t idx) const { return mVector[idx]; } //rhs or const version.
};
yes in C++ you can const_cast if you are in this case. But is very rare to do that. I use it maybe 2…3 times in my life. Usualy I have to cast away constness in flags in suposidly const objects when is expected a const behaviour but some unimportant things needs to be flagged. This are marginal uses.
But Julia functions don’t know anything about parameters or variables. They just see the values passed to them, and those values are either mutable or immutable. So the only avenue is to change the mutability state of the value. So if you want
foo(const a::MyType) = ...
foo(a::MyType) = ...
that would just be syntactic sugar for something like
foo(a::Const{MyType}) = ...
foo(a::MyType) = ...
and then you can select method by setting a to either point to a const or non-const value. This cannot be encoded into the variable a itself, separately from the value it points to, due to Julia being dynamically typed.
Isn’t the core issue here that you want Julia to be a fully statically typed language?
Julia is like many other languages, the parameters that you pass have a type and that type is used to specialise various implementations of a function. Julia is like C++ at compile time.
But that’s the thing: they don’t. The parameters have no type, only the values do. That’s the main difference between static and dynamic typing. I increasingly get the impression that this is a root of the confusion here: Variables do not have types, values have types, unlike in static languages, where variables do have type.
Are you not applying the static model to a dynamic language in this discussion?
Indeed they don’t but 100% of the time variables that you declare have a type. You should learn a bit at least about the types in Julia before writing. They are very cool.
That’s not the type of the variable a, it is the type of the value that a refers to.
I have been using Julia since 2014, or so, so I would appreciate it if you take a slightly less condescending tone (I have seen this through the entire thread, btw, not just now.)
At any given moment in time a declared variable has a type. If it has a type or reffers too is the same thing. Maybe you want to say that sometimes is a reference to a storage that store a type is correct too. But for simple types is NOT so! Simple types are passed by value so is not a “reffers to” but is the value.
Just use the suggestive called: typeof() on any value and you’ll see the current type.
No. This is (at least one of) the main difference between static and dynamic languages: that in static languages the variables have types, in dynamic ones they do not. This is apparently a deep (but understandable) confusion that you hold, due to having primarily experience with static typing. Until it is cleared up, it will be hard to get any further.
No.
No, all arguments are passed by sharing (Functions · The Julia Language). There is no difference in how they are passed. The only difference is that some values are mutable and some immutable. They are all passed according to the same semantics.
I haven’t read this long thread, but I do agree that C++ does const a lot better than Julia’s mutable struct vs struct. const also transitively applying to the fields of a struct and to pointers is great.
It’s silly that MArray and SArray should be two separate types in Julia IMO.
Rust does it even better. From this call site, can you guess which is a mutable borrow, which is immutable, and which is passed by value (which gives ownership in Rust, invalidating it in this scope): foo(&mut x, &y, z)
?
I think you are a bit confused by the “dynamic” buzzed word. With this powerful exprimation C is a “dynamic” language because has void*, macros and unions exactly how C++ is a “dynamic” language because it has void*, unions, templates, macros and any type. However all 3 languages: C, C++ and Julia at each moment in time have the declared variables having a type! That type at the momment of invocation is used to proper specialise functions.
It is very true that for simple types (Int, Float) the variable “stores” the data or refers or points to an individual place in memory and in the case of large objects containers, strings, tuples it stores a reference to same data. This is clear not relevant to the fact that ALWAYS any variable in Julia at any moment in time points to a well known type.
btw you can write how many NO you want I gave you plenty of examples to exemplify this. Please instead of NO give an example when the declared variable has no type. Obviously declared is declared not used as a template in a generic definition of a function. Don’t try with Nothing because is a known type.