That discussion was an eye-opener for me regarding type systems; to this day, I cringe when somebody calls, e.g. Python or Javascript a "typeless" languange.
That discussion was an eye-opener for me regarding type systems; to this day, I cringe when somebody calls, e.g. Python or Javascript a "typeless" languange.
There is some controversy over the strong/weak terminology, IMO mostly because almost no language is clearly strong or weak based on the definitions generally used[2]. I find it useful to think about whether things are done implicity, or whether you need to specifically convert types. Perl will happily add "1" and "1" to get 2, because the + operator forces it to be interpreted as a numeric type. Python will not, and expects you to convert to a numeric type first. Of course, exceptions to the rule abound.
1: http://stackoverflow.com/questions/2351190/static-dynamic-vs...
(0) Bash is strongly typed. Everything is a string, so there can't possibly be any type conversions, implicit or explicit.
(1) Any language with subtypes is weakly typed. For example, Haskell with Rank2Types or above: every lens is a traversal in a canonical way, and indeed the type checker lets you supply a lens in a context where a traversal is expected.
(2) Rust is even more weakly typed: boxes (as well as other user-defined pointer types) are implicitly converted to references, iterable objects are implicitly converted to iterators, etc.
There's no precise technical definition of "strongly typed", but AFAICT, the intuitive idea is that a "strongly typed" language prevents you, or at least makes it difficult to do things that aren't likely to make sense, like treating the same datum as a number and as a string in different places. This is independent of whether the language has implicit conversions.
If it were true that everything is a string, then yes, you probably could say it's strongly typed. It's laughable, but it is. Some single celled organisms are animals, as well. Assembly is generally the strongest typed language you can get.
But it's not true. Bash supports associative arrays.
#!/bin/bash
declare -A array_var
array_var=( ["foo"]="11" ["bar"]="22" );
echo "$array_var"; # Empty line
echo "${array_var[foo]}"; # 11
scalar_var="baz";
echo $scalar_var; # bar
array_var="quux";
echo "$array_var"; # quux
echo "${array_var[foo]}"; # 11
That said, I'm not sure if you can actually access the array container itself (I don't use bash for actual programming), so I'm not sure how it handles comparisons and operations between the types, if it's even possible. It may be Bash is strongly typed (I'm not sure), but we can't make that determination by assuming it has a single data type. Also, even if it was a single data type, there are interstitial types that exist for doing numeric operations, and I'm not sure how to consider those with respect to this concept.> (1) Any language with subtypes is weakly typed. For example, Haskell with Rank2Types or above: every lens is a traversal in a canonical way, and indeed the type checker lets you supply a lens in a context where a traversal is expected. > > (2) Rust is even more weakly typed: boxes (as well as other user-defined pointer types) are implicitly converted to references, iterable objects are implicitly converted to iterators, etc.
You're making very strong assertions based on my comment when I made sure to to say "almost no language is clearly strong or weak based on the definitions generally used", and even provided examples where the same language could be considered both strongly and weakly typed, depending on what aspect you were referring to.
"Strong" and "weak" are themselves relative terms, so make no sense unless comparing to something else. That may be a shared reference language, or the perceived common level of languages with respect to what is being discussed. I replied to the sibling of my original comment with some info about how I think about this. It's rarely useful to think of a language as entirely strongly or weakly typed, but certain aspects of it may or may not be (again, relative to some benchmark).
> There's no precise technical definition of "strongly typed", but AFAICT, the intuitive idea is that a "strongly typed" language prevents you, or at least makes it difficult to do things that aren't likely to make sense, like treating the same datum as a number and as a string in different places. This is independent of whether the language has implicit conversions.
Well, treating the same datum as a number and a string in different places is exacerbated by implicit conversions, which allow that behavior to succeed. I wouldn't say it's independent, I would say one depends on the other.
Really, whether they are well defined terms or not, I think it's still still useful to use them with some disambiguating context, as they express a concept otherwise hard to convey (if it was easy to convey, they wouldn't be so ambiguous in the first place).
I think a case could be made that any subversion of requiring the exact type defined or requiring manual conversion is a weakening of the type system, for the definition of weakening that we are using. The important consideration is that neither stronger nor weaker are always necessarily better or worse.
I didn't say it's the only useful thing, but it's perfectly reasonable to measure the expressive power of a type system (or any other language feature, really) by how much it buys you.
> can be seen as a weakening
Covariance and contravariance support by no means "weaken" a type system - they allow you to express more statically, not less.
That's exactly what expressiveness is. If a type system is versatile enough, you can express what you need to express without bypassing type safety.
> anything except the specified type
Even in this sense, subtyping doesn't weaken a type system. The definition of subtyping is the subsumption rule: given `S <: T` and `x : S`, you can derive `x : T`. (TAPL, p. 182) For similar reasons, adding ML-style let polymorphism to a type system doesn't weaken it.
> strong and weak is orthogonal to safety and expressiveness
Then what exactly is it?
I wouldn't say so. Perl is expressive. That expression sometimes comes at a cost of safety, but not always. Safety and expressiveness are not necessarily related.
> Then what exactly is it?
The exactitude of requiring exactly what is expected, and not allowing any substitutions. I'll explain my reasoning below.
> Even in this sense, subtyping doesn't weaken a type system.
Subtyping doesn't even always make sense when talking about strong or weak types. Some languages don't even have subtypes, yet we can still talk about how strong or weak their typing is just by referring to how different types interact, and whether conversion between them is implicit or explicit. Again, I'll call on Perl, which is useful in that it's very, very far from the type systems you have been describing WRT Haskell and Rust (and many languages that use static typing and inheritance).
Perl has two types of typing, variable (data structure) typing, and value typing. Perl is fairly strongly typed when it comes to variable types. It's either a scalar (which can contain many things, including references to other types), an array, which contains scalars, or a hash, which contains scalars (I'll leave out typeglobs and filehandles since they are fairly specialized). Until a few years ago, you could not supply a scalar where a hash or array was expected (e.g., you could not push($foo,"string"), you could only push(@foo,"sting"); ). You could explicitly dereference a scalar containing an array reference to an array and push to that, but it was an explicit dereference which required a @ prefixed the scalar[1].
Perl is fairly weakly typed when it comes to values within scalars. It will attempt to automatically convert the type to the appropriate representation such that the operation makes sense. Thus, adding two strings containing numbers requires no explicit conversion. Concatenating two numbers a string doesn't either. Neither do any string or numeric comparisons, as the conversion is implicit within the operator, as it knows what type it expects. This is why the expressions "1" + "2" and 1 . 2 in Perl are completely unambiguous. The first adds 1 and 2, yielding 3, the second concatenates the strings "1" and "2", yielding "12". The original type presented doesn't matter, it's implicitly converted as needed.
Subtyping, in this case, is irrelevant, because it doesn't exist in this language for these types of typing. It's entirely valid to talk about strong and weak typing in both these aspects or Perl, but they are both different and neither really matches the typing you are referring to with "type systems", because this language functions at a different level. The only way I can see using strong or weak typing as a descriptor across many languages, is to define it as how exact the type of data you are supplying needs to be to match what is expected. That is "strong" has entirely to do with constraints and explicitness. Anything that allows implicit action, even using a subtype which is known to be safe without some indication that you are raising or lowering the type explicitly so it can be used, is a weakening of that constraint (even if it's provably safe. Again, we aren't saying it's strongly safe, just that it's strongly constrained by type).
This reasoning leads to one of your original examples questions:
> Rust is even more weakly typed: boxes (as well as other user-defined pointer types) are implicitly converted to references, iterable objects are implicitly converted to iterators, etc
Yes. In some aspects, Rust has weakened it's typing in very specific circumstances to allow for more expressive programming, by not requiring explicit conversion when it can be inferred by the compiler. In this respect, Rust is more "weakly" typed that it could be, but it's also no less safe, no less fast, and more expressive for doing so, which I'm sure we would both agree is a good trade-off to make in this instance.
I hope that explains my view, and my reasoning, sufficiently. Let me know anything about my reasoning that confuses you, and I'll try to explain better (and of course feel free to poke holes where you see them).
1: Perl experimented with allowing core functions that expected an array or hash to allow a scalar containing a reference to such to work without the dereference, but ended up backing out that change.
Sure, but I was talking about the expressiveness of the type system, not the term language. The expressiveness of a type system lies in how much it tells you about your program, without having to actually run it.
> Rust has weakened its typing
I was trying to use reductio ad absurdum to question the validity of your definitions. I expected "Haskell is weakly typed" and "Rust is weakly typed" to be self-evidently false propositions.
Expressiveness can be described as expressiveness. I'm not sure why we would need to use strong/weak as an alternative to that term. IMO, it makes the strong/weak terminology less useful by tying it to this concept, which is only really relevant in some languages.
> I was trying to use reductio ad absurdum to question the validity of your definitions. I expected "Haskell is weakly typed" and "Rust is weakly typed" to be self-evidently false propositions.
I'm not sure if this is implying that we disagree on something that you still see to be self evident, or it's meant to explain why you included that and you no longer think it's a position worth holding?
In any case, I think it's worth clarifying that I didn't call Rust weakly typed, I said it hda weakened it's type constraints in a select few cases to increase expressiveness, where it did not cost in safety. (Constraints because everywhere you put strong/weak I think you can append constraints to be more explicit). I don't think it's controversial to say "Rust weakened constraints the type system imposed in some cases where it could be done safely, such as in iterable objects implicitly being seen as iterators in some cases", as that's clearly a bit less constrained than it could be.
Expressiveness is always relative to what a system is meant to express. The purpose of a type system isn't to write your actual programs in it. You use a type system to make sure that programs written in another language (a term language) make sense. So a type system is expressive to the extent it accurately captures the distinction between programs that make sense and programs that don't. (Of course, Goedel tells us that no decidable type system can perfectly capture this distinction.)
As for strong/weak, I don't think the concept is very useful without a clear technical definition in the first place.
Well, it's definitely not very useful in our case. ;) In all seriousness, as I said previously, I think it's useful for conveying a mixed bag of things to people that aren't very well versed in the specifics. If the person knows something about type systems, you should naturally have more specific language to fall back on to express your intent better.
In any case, I think we are way past of this being worthwhile to continue. I think we've plumbed the depths of this topic, whether we agree or not.
> Rust is even more weakly typed
Both of your examples here happen in much more limited circumstances than you seem to imply.There is no generally agreed upon definition of what the distinction means.
Second, the context here is whether or not the type system of a language is strong or it is weak.
I stand by my assertion that describing type systems as strong or weak typing is essentially meaningless. It's so far from descriptive that all 'strongly typed' ever really means is 'I like this feature' and 'weakly typed' means 'I do not like this feature'.
There are alternative, accurate ways of talking about what people think they are trying to get at when they use the terms strong and weak in relation to languages. They should be used instead.