<p>According to <a href="https://en.wikipedia.org/wiki/Strong_and_weak_typing" rel="nofollow noreferrer">Wikipedia</a>, the terms &quot;strongly typed&quot; and &quot;weakly typed&quot; do not have agreed-upon formal definitions:</p>
<blockquote>
<p>there is no precise technical definition of what the terms mean and different authors disagree about the implied meaning of the terms and the relative rankings of the &quot;strength&quot; of the type systems of mainstream programming languages.</p>
</blockquote>
<p>Wikipedia cites <a href="https://blogs.perl.org/users/ovid/2010/08/what-to-know-before-debating-type-systems.html" rel="nofollow noreferrer">a 2010 blog post</a> by <a href="https://ovid.github.io/" rel="nofollow noreferrer">Curtis Poe</a> for this claim, but the blog post doesn't cite any sources itself, and is written in a quite opinionated way (emphasis in original):</p>
<blockquote>
<p>Probably the most common way type systems are classified is &quot;strong&quot; or &quot;weak.&quot; This is unfortunate, since these words have nearly no meaning at all. It is, to a limited extent, possible to compare two languages with very similar type systems, and designate one as having the strong<strong>er</strong> of those two systems. Beyond that, the words mean nothing at all.</p>
<p>Therefore: I give the following general definitions for strong and weak typing, at least when used as absolutes:</p>
<ul>
<li><strong>Strong typing:</strong> A type system that I like and feel comfortable with</li>
<li><strong>Weak typing:</strong> A type system that worries me, or makes me feel uncomfortable</li>
</ul>
</blockquote>
<p>Given the age and informality of the source, is this claim true? What <strong>authoritative</strong> definitions are there for &quot;strong&quot; and &quot;weak&quot; typing, and is there disagreement on these terms between different authorities?</p>
<hr />
<p>To clarify what counts as &quot;authoritative&quot;, see Wikipedia's rules for <a href="https://en.wikipedia.org/wiki/Wikipedia:Reliable_sources" rel="nofollow noreferrer">reliable sources</a> (also <a href="https://en.wikipedia.org/wiki/Wikipedia:Verifiability#Reliable_sources" rel="nofollow noreferrer">here</a>):</p>
<blockquote>
<p>If available, academic and peer-reviewed publications are usually the most reliable sources on topics such as [...] science. [...] Other reliable sources include:</p>
<ul>
<li>University-level textbooks</li>
<li>Books published by respected publishing houses</li>
<li>Mainstream (non-fringe) magazines, including specialty ones</li>
</ul>
</blockquote>
<blockquote>
<p>Self-published expert sources may be considered reliable when produced by an established expert on the subject matter, whose work in the relevant field has previously been published by reliable, independent publications.</p>
</blockquote>
<p>Wikipedia's article does refer to some definitions from academic literature, but these seem to describe static typing and type safety, which are usually considered distinct concepts to strong typing.</p>

<types><terminology>
How are "strong" and "weak" typing defined?
CC BY-SA 4.0
2024-04-27T16:58:42.253Z
See the related Wikipedia article on [type safety](https://en.wikipedia.org/wiki/Type_safety#Strong_and_weak_typing).  In particular one aspect of type safety is [compile-time type checking](https://stackoverflow.com/questions/260626/what-is-type-safe) and c.f. related posts at StackOverflow.
hardmath
CC BY-SA 4.0
2024-04-27T17:05:26.373Z
I would guess that most programming languages textbooks would contain a definition or at least some sort of discussion.  Starting point: [*The Structure of Typed Programming Languages* by David A. Schmidt](https://www.google.com/books/edition/The_Structure_of_Typed_Programming_Langu/Ax2QXEwXhzQC?hl=en&gbpv=1&dq=strongly%20typed&pg=PA6&printsec=frontcover) "A language with static typing is *strongly typed* if no well-typed program produces run-time incompatibility errors."
Nate Eldredge
CC BY-SA 4.0
2024-04-27T17:07:55.053Z
@NateEldredge This seems to describe what we normally call type safety or soundness, and doesn't tell us what it means for a dynamically-typed language. If there are no reliable sources which distinguish between strength and safety/soundness, though, then an answer which establishes that would also be good.
kaya3
CC BY-SA 4.0
2024-04-27T18:07:58.480Z
I wonder if there is some distinction where you can have dynamically typed languages that are *technically* type safe (because the way the error messages work are fully defined) in contrast to languages where type errors produce runtime behavior which cannot really be (fully) defined (such as potential segfaults).
David Young
CC BY-SA 4.0
2024-04-27T18:45:54.280Z
I think there is a real difficulty with this question because the premise *is* true — there isn’t an established, agreed definition, so “authoritative” sources either don’t define it (because the definition would be wrong sometimes) or use a local definition that is inconsistent with others. On the other hand, people do use those terms with locally-consistent meaning. Is an answer just a survey of different publications and how they use it?
Michael Homer
CC BY-SA 4.0
2024-04-27T19:00:09.083Z
@MichaelHomer A survey of how the term is defined (or at least used) in different publications would be good; even better with some analysis of how they agree or disagree on the term's meaning.
kaya3
CC BY-SA 4.0
2024-04-27T20:18:50.853Z
It would also be interesting to see where there might be agreement in the different definitions. For instance, I'd be pretty surprised to see any definition where C is "strongly typed."
David Young
CC BY-SA 4.0
2024-04-27T20:35:41.730Z
Well if I'm an authority then: I agree with Curtis. Is C# strongly typed? It has many features that people describe as "strong" and many features that people describe as "weak".  If you mean "allows casting", say "allows casting", not "weak".  If you mean "objects can describe their types" then say "objects can describe their types", not "strong".
Eric Lippert
CC BY-SA 4.0
2024-04-27T20:51:09.097Z
@EricLippert Curtis's post seemed to me a bit too polemic to be an accurate reflection of how the terms would be used by experts, but if the reason they lack formal definitions is because experts don't find the terms to be useful, then perhaps I should take his post more literally. If there is evidence that experts in general avoid these terms for that reason then that would make a great answer, and perhaps convince more people to stop using them in favour of clearer descriptors.
kaya3
CC BY-SA 4.0
2024-04-28T08:10:08.473Z
Found [What does weak static typing/strong dynamic typing mean?](https://softwareengineering.stackexchange.com/q/297653/439060) on the Software Engineering stack. One answer does contain ``It makes a "great" argument in a flamewar`` about asking for the meaning of _strongly typed_ and _weakly typed_.
Chester Gillon
CC BY-SA 4.0
2024-04-28T13:56:55.167Z
@ChesterGillon Good find; especially the quote by Benjamin Pierce. The source for that quote seems to be [a Reddit comment](https://www.reddit.com/r/programming/comments/t7v9/comment/ct8je/) by Mark Jason Dominus.
kaya3
CC BY-SA 4.0
2024-04-28T16:33:49.343Z
"Weak" means a type system that the person you're talking to doesn't like. ;-)
Glenn Willen
CC BY-SA 4.0
2024-04-29T23:40:27.237Z
First we need to understand, *what is a type*. A type is *a set of possible values*. For example, `uint16_t` in C has a very clearly defined, not very big set. Other types are more hard to define, but what we always find, that is *the set of values*. That is the idealistic part of this post. In this sense, we can talk about "typed" and about "typeless" languages, as two extremes. In practice, in the engineering practice, these are only ideas and the real programming languages stay somewhere between these extremes. We can call "weakly typed" the languages more close to the typeless langs.
peterh
CC BY-SA 4.0
2024-04-30T15:41:17.720Z
@peterh I've long thought that "a set of possible values" is one view of what a type is, but not a complete view. In TypeScript for example `{x: number} | {x: string}` is not the same type as `{x: number | string}` despite the two value sets being the same. And once you start considering generics, two function types might end up having the same set of values, e.g. `() => []` is (essentially) the only value of type `() => []` but also the only value of type `<T>() => T[]`, and the only value of type `<T extends Foo>() => T[]`.
kaya3
CC BY-SA 4.0
2024-04-30T17:21:01.263Z
It's really a sliding scale that depends on how much the language implicitly converts types. Perl is on the weak end, Haskell is on the strong end, and C is somewhere in the middle. Where exactly a person might draw the line between weak and strong typing comes down to preference.
Beefster
CC BY-SA 4.0
2024-04-30T17:24:11.783Z
@Beefster I'm aware of the popular definition that strength/weakness is about implicit conversions (aka coercion); this is also already covered in the accepted answer. The question is about authoritative definitions, so if you have an authoritative source for this definition then that would be relevant.
kaya3
CC BY-SA 4.0
2024-04-30T21:22:34.563Z
@kaya3 I think we should differentiate between type as the element of a set, and type as the language defines it. Even if TypeScript has this... *nuance*... you still can say of "anything" if it is a `number | string` or not. Also generics, function types don't change it. You still can say from everything, if it is one of not. Question if, how important is it for the language, is that thing an element of that set or not.
peterh
CC BY-SA 4.0
2024-04-30T21:28:40.590Z
@peterh That distinction between types and sets actually [runs quite a bit deeper than just "language quirks"](https://cs.stackexchange.com/a/91345/20578).
David Young
CC BY-SA 4.0
2024-04-30T21:54:05.920Z
@peterh I don't think this is at all a quirk of TypeScript. Consider two classes like `final class Foo { private Foo() { throw new RuntimeException(); } }` and `Bar` defined similarly in Java; the types `Foo` and `Bar` admit only the value `null`, but they are not the same type. Also consider type erasure: technically in Java every value of type `List<String>` could be held by a variable of type `List<Integer>` and vice versa, via casts using the bare type `List`; but of course they are not the same type.
kaya3
CC BY-SA 4.0
2024-04-30T21:56:29.757Z
In general, you may use any valid mathematical proof to show that two sets are equal; but a type system defines a much more limited set of rules, and types are only equivalent in that system if they can be proved using those rules.
kaya3
CC BY-SA 4.0
2024-04-30T22:54:41.660Z
@DavidYoung Wow, right :-) I am thinking, thanks the link.
peterh
<p>I recommend <a href="https://langdev.stackexchange.com/a/3742/5222">Michael Homer's answer</a>, though I would like to offer a definition of these terms I learned in university (circa 2017) that I find sensible.</p>
<p>Essentially, a &quot;weakly typed&quot; programming language is one <strong>in which there exists one or more ways, within the language's spec, to circumvent its type system and ~~cause undefined behavior~~ break code the relies on its assumptions, requiring analysis at a lower level to understand it.</strong> (<strong>EDIT:</strong> TypeScript presents an interesting caveat that forces me to generalize this definition - see below.) A &quot;strongly typed&quot; programming language is simply defined as having no such holes - the type system, no matter what it is, follows its stated rules.</p>
<p>Note that this is distinct from &quot;static typing&quot; vs. &quot;dynamic typing&quot;, which are better defined. A <strong>statically typed</strong> language is one in which the types of its values can be determined at compile time, usually accompanied by an explicit requirement to declare the types of local/global variables, function arguments, and return values. In a <strong>dynamically typed</strong> language, the type information is handled internally within the variables at runtime, with the language not concerning itself with the value's type until it's necessary to do so.</p>
<p>JavaScript, for instance, is dynamically but strongly typed. Variable types are kept internally and there's no way to declare which ones are what (and you can end up with variables with the wrong type at runtime), but the type system has well defined rules for all eventualities - as long as no FFI code is involved, you can follow the code from the beginning, where each and every variable is instantiated, and use the language rules to know exactly what that code is going to do. Yes, you get an error if you try to call a method that doesn't exist on an object, but because the JavaScript runtime has exact rules on what happens when you look up a property that doesn't exist (getting the special value <code>undefined</code>) and what happens when you run the call operator on a value (such as <code>undefined</code>) that doesn't support it (you get a <code>TypeError</code>), the type system is still strong.</p>
<p>Contrast that with C, which is statically but weakly typed. All variables have a specific type associated with them, which you have to declare (unless you're using a variant that lets you use <code>auto</code> to declare a variable if its type can be exactly inferred from the incoming expression). Most expressions have specific rules for what types can be used together and when type casts occur (including implicit type casts). However, because dereferencing an invalid pointer value causes undefined behavior, and <em>arbitrary integers can be bit-cast to pointers</em> (including invalid ones), it is possible to circumvent C's type system - hence, C is weakly typed.</p>
<p>Rust is an interesting case - safe Rust (barring any design flaws) is strongly and statically typed, while unsafe Rust is weakly and statically typed. In both cases, the type system has well-defined rules (including rules with lifetimes, which are part of the value types for each variable and expression), but in unsafe Rust, some actions that break the type system and cause undefined behavior are possible, and it is up to the programmer to ensure that they are keeping the well-defined rules within the confines of the <code>unsafe</code> blocks.</p>
<p>On this note, I would not consider implicit type coercion to be an example of a weak type system, as long as the rules themselves for when this occurs are well defined. For instance, the language might go &quot;oh, look at me! I'm going to cast this int to a float without telling you!&quot; but as long as it defines <em>why</em> it thinks it's OK to cast the int to a float, and how exactly it's going to go about it, it's still well defined. Direct bit casting, as well, is not reason enough to declare a type system weak as long as 1) the values you're casting <em>to</em> and <em>from</em> have well-defined bit patterns, and 2) the value you're casting to doesn't have any invalid values (or the language at least has a well-defined rule for how to deal with these invalid values). I would not consider using silent failure values (e.g. using <code>NaN</code> for floating point errors, using <code>undefined</code> for missing a property lookup) to be indicative of a weak type system either, as long as the language has well-defined rules for when those error values appear and how those error values behave.</p>
<p>And this brings me to my last point: nothing about the &quot;strength&quot; or &quot;weakness&quot; of a type system, under this definition, has anything to do with what the programmer might want out of a type system. I would definitely argue that implicit casts, reckless reinterpret casting, and silent failure values are <em>bad</em>, but that opinion is ultimately subjective - some other programmer, at some other time, wanted those features in their language and defined rules for how they should work. Rather, the primary meaning of the strength or weakness of a type system, under this definition, <strong>is its ability for a program written under that type system to reliably undergo a security audit.</strong> Regardless of what the actual rules for the type system are, and whether you actually want to use them, if you can at least use the type system to reliably predict what a program is going to do given specific inputs (because none of the rules of the type system can be broken by other parts of the program), then it's a strong type system. A weak type system cannot reliably undergo such an audit, and programs must instead be analyzed at a lower level (i.e. debugging at the assembly code level on the target machine) to figure out what it's doing when it's not behaving properly.</p>
<p><strong>ADDENDUM:</strong> Some other examples:</p>
<ul>
<li>Lambda calculus is statically and strongly typed, even though it doesn't have any type declarations (and is often considered &quot;typeless&quot;). This is because every single value has the same type: a function that takes one argument and returns one value (each of which is also a function that takes one argument and returns one value, and so on). The only allowed operations on these values are either calling them or composing them, which makes sense for these kinds of values.</li>
<li>Python is dynamically and strongly typed for much the same reasons as JavaScript - again, as long as no FFI code is involved, you can follow the code from the beginning and determine which values are what type, even though the language does not enforce these in the syntax.</li>
<li>Assembly code is dynamically typed, in that everything is just a set of bits and is treated as a particular kind of value upon running a specific instruction. Whether or not it's strongly or weakly typed is going to depend on the system it's running on top of, as that's where most of the actual definition of the assembly code comes from (though I think it'd be fair to call assembly language weakly typed on pretty much any platform, since system calls/interrupt vectors have different types, and there's probably at least one address that leads to invalid, undefined behavior when read to or written from from an arbitrarily constructed pointer).</li>
<li>TypeScript presents an extremely interesting case: by this definition, it is actually <em>weakly</em> typed while JavaScript is strongly typed, paradoxically enough. This is because TypeScript, while providing incredible and flexible static type specifications with structural types/algebraic types/true top and bottom types, lets developers lie about all of this through type assertions, and must descend to a lower layer to understand the program when this happens. However, since JavaScript is strongly (although dynamically) typed, you only have to descend to that level, while a type-circumvented C program requires descending to assembly or further.</li>
</ul>

CC BY-SA 4.0
2024-04-29T17:44:30.230Z
2024-06-09T15:34:31.077Z
2024-06-09T15:34:31.077Z
TheHans255
CC BY-SA 4.0
2024-04-29T17:51:47.957Z
Welcome! The definition in your second paragraph looks like what we would normally call "[memory safety](https://en.wikipedia.org/wiki/Memory_safety)" - if there is a source for this as a definition of strong typing (e.g. your professor's lecture slides) it would help to add a link. Also, your first paragraph suggests you learned more than one definition in university, but I don't see any others (though you refer to coercion as *not* a definition).
kaya3
CC BY-SA 4.0
2024-04-29T18:04:19.120Z
@kaya3 I'll see what I can find - it was forever ago. By "some definitions", I meant to imply "a definition each for strong, weak, static, and dynamic" - I'll change it to "a definition" since those definitions are linked.
TheHans255
CC BY-SA 4.0
2024-04-29T18:15:17.680Z
Fair enough. I think the edit makes this clearer.
kaya3
CC BY-SA 4.0
2024-04-29T20:19:04.760Z
Minor quibble: in JavaScript, you can create a variable, assign it a value, and then assign it another value, and the types of the two values need not be compatible. In my mind, this makes JS weakly typed, as it enforces nothing about the type of the variable.
JakeRobb
CC BY-SA 4.0
2024-04-29T20:23:57.257Z
@JakeRobb That's correct, and it does disqualify JS from being statically typed. I would not consider it weakly typed, however, since JavaScript has well-defined rules of how reassigning a variable with another value of a different type is supposed to work (since it looks at the type of the actual value at runtime and enforces its rules from there). It wouldn't be any different from having a Java variable of type `java.lang.Object`, for example.
TheHans255
CC BY-SA 4.0
2024-04-29T20:47:50.487Z
I can't think of any languages that don't care about the type of a _value_; leaning toward that not being possible. My point is about caring about the type of a _variable_ (i.e. the value's container). If you have a Java variable of type `j.l.Object`, you do need to assign it a value consistent with that type. Since Java 1.5 we have autoboxing (a limited form of compile-time type coercion), which makes it semantically impossible to violate that rule, but in the old days you could try to do it, and Java's strong typing compiler prevented you from doing so.
JakeRobb
CC BY-SA 4.0
2024-04-29T20:57:29.793Z
@JakeRobb Forth does not care about types in any way, as far as I know. Assembly languages tend to be typeless. The untyped lambda calculus is typeless (appropriately enough).
David Young
CC BY-SA 4.0
2024-04-29T21:08:55.360Z
Assembly language types are generally just chunks of bits -- byte, word, etc. If I'm not mistaken, some modern processors do enforce that you're not passing, say, a memory address in when a value is expected....
JakeRobb
CC BY-SA 4.0
2024-04-29T21:26:19.867Z
@JakeRobb re: Java - what I meant to convey is that JavaScript's type system is basically equivalent to having a Java program where _every single variable_ is declared as `Object`. It's possible to store any type of value in such a variable (either through direct storage or autoboxing), but the language would not let you call any method more specific than the Object base methods without some amount of runtime type checking or runtime reflection (such as looking up methods by string name, which is exactly what JavaScript does).
TheHans255
CC BY-SA 4.0
2024-04-29T21:29:22.360Z
I guess I see what you're saying, but conflating direct storage with autoboxing misses my point entirely. Java only demonstrates the difference if you acknowledge that autoboxing is a thing. You can't store a primitive in an Object, because Java doesn't let you, and that's what I claim is the key behavior of a strongly typed language (although I can find no authoritative source to support me on that).
JakeRobb
CC BY-SA 4.0
2024-04-29T21:36:13.260Z
@JakeRobb That is a fair point, and I would consider that an example of both strong and static typing in Java - if you have a JVM `a` (reference) type, for instance, it's guaranteed to either be `null` or a pointer to a valid object, not just some random mishmash of bits that we're interpreting that way. I would just argue that if we had a version of Java where the primitive/reference distinction did not exist (i.e. everything lives in a boxed reference) and all variables are declared as `Object`, the language would still be strongly typed, just not statically typed.
TheHans255
CC BY-SA 4.0
2024-04-30T17:13:44.707Z
The same "unsafe" distinction appears in C#. At least, to the best of my understanding, it works essentially the same way in Rust that it does in C#.
Karl Knechtel
CC BY-SA 4.0
2024-04-30T17:30:26.293Z
I don't think reinterpret casts inherently make a type system weak. That's a perfectly reasonable and well-defined behavior, albeit one that depends on the internal bit representation. I think the main aspect of C that makes its type system "weak" is that pointer conversions are implicit and silent. Contrast to something like Zig or Odin, which allows reinterpret casts, but only explicitly. Perl and Javascript both do a lot of implicit conversions between numbers and strings, leading to lots of surprises even though the behavior is well-defined.
Beefster
CC BY-SA 4.0
2024-04-30T18:09:42.660Z
@Beefster Agreed. As I say further down in my post, I think that reinterpret casting creates a weak type system if and only if you are able to cast a _valid_ value from the source type into an _invalid_ value for the destination type, such that the language does not define what happens if you use the invalid value. The silent implicit conversions are definitely _bad_, and a language that requires explicit conversions is better, but Perl and JavaScript's implicit conversions aren't going to make demons fly out your nose.
TheHans255
CC BY-SA 4.0
2024-04-30T22:55:54.620Z
C is statically typed if one ignores type-based aliasing analysis.  The Standard's rules for TBAA, however, assume dynamic typing in ways that yield unworkable corner cases.
supercat
<p>The AdaCore <a href="https://learn.adacore.com/courses/Ada_For_The_CPP_Java_Developer/chapters/05_Type_System.html#strong-typing" rel="nofollow noreferrer">Strong Typing</a> section of <a href="https://learn.adacore.com/courses/Ada_For_The_CPP_Java_Developer/index.html" rel="nofollow noreferrer">Ada for the C++ or Java Developer</a> starts with (emphasis mine):</p>
<blockquote>
<p>One of the main characteristics of Ada is its strong typing (i.e., <strong>relative</strong> absence of implicit type conversions). This may take some getting used to. For example, you can't divide an integer by a float. You need to perform the division operation using values of the same type, so one value must be <strong>explicitly converted</strong> to match the type of the other (in this case the more likely conversion is from integer to float). Ada is designed to guarantee that what's done by the program is what's meant by the programmer, leaving as little room for compiler interpretation as possible.</p>
</blockquote>
<p>So, in the above guide AdaCore define <em>strong typing</em> as the relative absence of <em>implicit</em> type conversions.</p>
<p>The other <a href="https://langdev.stackexchange.com/a/3742/1044">answer</a> contains the following about <em>weak typing</em>:</p>
<blockquote>
<p>A weakly-typed language is one where the bits of a value can be reinterpreted as another type ...</p>
</blockquote>
<p>The AdaCore <a href="https://learn.adacore.com/courses/Ada_For_The_Embedded_C_Developer/chapters/06_Translation.html" rel="nofollow noreferrer">C to Ada Translation Patterns</a> section of <a href="https://learn.adacore.com/courses/Ada_For_The_Embedded_C_Developer/index.html" rel="nofollow noreferrer">Ada for the Embedded C Developer</a> two ways in which Ada allows the <em>bits of a value</em> to be reinterpreted in the <a href="https://learn.adacore.com/courses/Ada_For_The_Embedded_C_Developer/chapters/06_Translation.html#overlays-vs-unchecked-conversions" rel="nofollow noreferrer">Overlays vs. Unchecked Conversions</a> section reinterpretations of bit values:</p>
<ol>
<li>Overlays using an <code>Address</code> clause.</li>
<li>Unchecked Conversions, by instantiating a <code>Unchecked_Conversion</code> generic.</li>
</ol>
<p>So, a language described has having <em>strong</em> typing may have language features or standard library functions which still allow reinterpretations of bit values.</p>

CC BY-SA 4.0
2024-04-28T08:27:20.187Z
2024-04-28T08:27:20.187Z
Chester Gillon
CC BY-SA 4.0
2024-04-28T09:15:40.820Z
I'm not sure how sound "implicit type conversion" is as a rule. If I can divide an `int` by a `float` because the languages let's `int / float` match `int / float`, is that implicit type conversion? If I can divide an `int` by a `float` because the language defines `int / float` to do the conversion explicitly but under the hood, is that implicit type conversion? A lot of languages allow `int / float` without technically using implicit conversions.
MisterMiyagi
CC BY-SA 4.0
2024-04-28T13:49:15.357Z
@MisterMiyagi I don't know any language which defines `int / float` in any other way than "coerce the int to a float, then divide". In Java this is called a "[widening primitive conversion](https://docs.oracle.com/javase/specs/jls/se18/html/jls-5.html#jls-5.1.2)", for example. It would be difficult to define it any other way, since IEEE 754 doesn't specify any binary operations on floating point numbers where the other operand is not a floating point number.
kaya3
CC BY-SA 4.0
2024-04-28T14:58:12.327Z
@kaya3 IEEE 754? Thousands of languages were created before it was first defined in 1985, so a huge number of languages aren't going to define it based on what IEEE 754 says.
prosfilaes
CC BY-SA 4.0
2024-04-28T15:12:04.653Z
@kaya3 I'm not sceptical about the `int` value being converted to a `float` value, but about that being done necessarily as an implicit type conversion (via coercion as in your example). Any language that allows for explicit type conversions and operators can trivially define this via those mechanisms, without the type system doing anything implicitly.
MisterMiyagi
CC BY-SA 4.0
2024-04-28T15:18:33.903Z
@MisterMiyagi In what sense is the conversion in `int / float` not implicit, if it is not written explicitly like `((float) x) / y`? It doesn't matter how that is implemented, whether by operator overloading or otherwise.
kaya3
CC BY-SA 4.0
2024-04-28T15:20:43.773Z
@prosfilaes Unless any of those languages define `int / float` in a way which doesn't coerce the int to a float, that is irrelevant to my point.
kaya3
CC BY-SA 4.0
2024-04-28T16:12:00.967Z
@kaya3 "It doesn't matter how that is implemented, whether by operator overloading or otherwise." It seems pretty pointless to classify the type system of a language by the rules implemented by a program. There's a good chance that someone, somewhere, out there overloaded some operator to accept mismatching types.
MisterMiyagi
CC BY-SA 4.0
2024-04-28T17:48:01.483Z
@MisterMiyagi We are talking about the behaviours of built-in operators on built-in types. If the implementation details of that matter, then "language X has implicit conversions" is a meaningless statement because one implementation might satisfy your definition of "implicit conversions" and another might not, despite both implementations behaving identically. It is much more sensible to say that an implicit conversion is a type conversion which is not explicit in the code where the conversion occurs. In `int / float` there is a conversion from int to float without any syntax indicating it.
kaya3
CC BY-SA 4.0
2024-04-28T17:49:32.330Z
To allay your concern about "classifying type systems", implicit conversions are a feature of the language's semantics as a whole, not of the type system alone. The fact that an `if` statement in Python coerces the condition's value to a `bool` is a fact about Python's `if` statements, not a fact about Python's type system.
kaya3
CC BY-SA 4.0
2024-04-28T17:57:07.310Z
To me it would be extremely perverse to say that both `x / y` and `((float) x) / y` explicitly convert `x` to a float, when one has an explicit cast and the other does not; and it would be just as perverse to say that `x / y` does not convert `x` to a float but `((float) x) / y` does, when these terms have exactly the same operational semantics. So it is inescapable both that `x / y` performs a conversion, and that the conversion is not explicit. The word for "not explicit" is "implicit".
kaya3
CC BY-SA 4.0
2024-04-30T17:29:51.803Z
@kaya3 My objection is that "convert" and "coerce" do not mean the same thing. If I write `float(x) / y` in Python (assuming a 3.x version in the CPython implementation) then an entire new object is created (a conversion) to represent the floating-point value numerically equal (within the limits of the precision of floats) to `x`. With `x / y`, the underlying value of `x` is coerced to a floating-point bit representation, within the underlying C runtime, only because the hardware demands it. There is nothing *inherent to* the concept of division that requires the operand types to match.
Karl Knechtel
CC BY-SA 4.0
2024-04-30T17:30:17.820Z
And yes, I'm aware early versions of Python had a `coerce` builtin and `__coerce__` dunder. Aside from being a design mistake, the name was also simply wrong. Conversion creates a separate object, even if short-lived, that is expected to follow the language's object semantics. Coercion is an in-place reinterpretation, whether permanent or only for the duration of the operation.
Karl Knechtel
CC BY-SA 4.0
2024-04-30T17:32:25.230Z
@KarlKnechtel [A coercion is an implicit conversion](https://en.wikipedia.org/wiki/Type_conversion#Implicit_type_conversion). I don't see how it matters whether the converted value exists in memory while the operation is applied; that is an implementation detail, you could perfectly well implement Python according to the spec without creating a new `float` object at runtime. It would still be the same language with the same semantics. What matters is that an expression of type `int / float` is operationally defined (in Python and C) as converting the int to a float and then dividing as floats.
kaya3
CC BY-SA 4.0
2024-04-30T17:37:12.270Z
"It would still be the same language with the same semantics." The point is that, among other things, when you call `float(x)`, `float` has to be looked up (the name could have been rebound). You *have to* create a new `float` because the `float(x)` subexpression is separately meaningful. The Python developers are quite insistent on this. You get different bytecode and you are expected to be able to see the difference with the built-in debugger. It is very much considered part of the language's semantics.
Karl Knechtel
CC BY-SA 4.0
2024-04-30T17:38:35.793Z
@KarlKnechtel I don't see how that is relevant to any point being made here. In an expression `x / y` where an int is divided by a float, there is no explicit conversion and hence no need to look up the name `float` to find the function, since that function is not called in this expression. Particularly, even if you rebind the name `float` in Python, `x / y` will still convert the integer to a float before dividing as floats. There is also no need to look up `float` by name when doing explicit conversions in C or Java, which also do this coercion for dividing ints by floats.
kaya3
CC BY-SA 4.0
2024-04-30T17:43:00.130Z
You say that this conversion occurs in C "only because the hardware demands it", but it is also part of the C specification (likewise Java) that the result of the division is what you would get by converting the int to a float and then dividing as floats. Whether a conversion is carried out by the hardware is an implementation detail, but nonetheless an implicit conversion is part of the specified semantics of the language. As mentioned above, Java calls it a "widening primitive conversion", so to insist that it is not a conversion seems silly.
kaya3
CC BY-SA 4.0
2024-04-30T17:45:41.907Z
You say *"There is nothing inherent to the concept of division that requires the operand types to match"*, but we are not talking about the concept of division, we are talking about the `/` operator in a programming language which has a specification, and that specification says there is a type conversion.
kaya3
CC BY-SA 4.0
2024-04-30T17:51:31.490Z
You also say *"With `x / y`, the underlying value of x is coerced to a floating-point bit representation, within the underlying C runtime"*, but [that is not actually true in CPython](https://github.com/python/cpython/blob/4a5ad8469af9a6fc0ec1355eb203cc22bb4321d5/Objects/floatobject.c#L618); it still creates a new `float` object at runtime (the `CONVERT_TO_DOUBLE` macro does this by reference). Not that this matters, because my point is about the language's semantics, not the implementation.
kaya3
CC BY-SA 4.0
2024-04-30T17:54:50.987Z
[Quoting the Python spec](https://docs.python.org/3.12/reference/expressions.html#binary-arithmetic-operations), *"The numeric arguments are first converted to a common type."*.
kaya3
<p>For me, strong and weak typing imply that the compiler, runtime, or anything else (other than the code you write) is <em>enforcing something</em> about the types of various pieces of data. Variables, arguments, return values, etc (which I will refer to as &quot;variables&quot; henceforth).</p>
<p>The &quot;something&quot; part is indeed arbitrary, but when we constrain the domain to data types, to my mind it really only leaves one thing that <em>could</em> be enforced. Dynamic typing, duck typing, type inference, type coercion, and other features of a type system are not important, because they are not about enforcement.</p>
<p>A strongly typed language enforces that when a variable is declared, it is assigned a type (explicitly or implicitly), and for the duration of the variable's lifecycle, it will continue to have that type and only that type. A weakly typed language doesn't do this.</p>
<p>Let's pick on JavaScript as an example of a weakly typed language. The following is entirely reasonable:</p>
<pre class="lang-js prettyprint-override"><code>var a = 123; // a has type number
a = &quot;123&quot;; // now a has type string.
</code></pre>
<p>And then let's contrast with JavaScript's strongly typed (IMO) cousin, TypeScript, in which the same code is not permitted.</p>
<pre class="lang-ts prettyprint-override"><code>var a = 123; // a has type number
a = &quot;123&quot;; // doesn't compile
</code></pre>
<p>JavaScript's type-related weakness goes beyond this enforcement with type <em>coercion</em>, but that's entirely separate from being weakly typed (i.e., you could have a language with one but not the other). That said, type coercion and weak typing go hand-in-hand in several ways, not least of which is the fact that they both allow subtle bugs to sneak into code way too easily for my personal taste. </p>
<p>There are plenty more examples of weakly typed languages (Shell comes to mind). There's nothing wrong with them, but personally, I try not to use them in complex and/or production systems if I have a choice.</p>
<p>EDIT: apologies; I missed that the question is looking for authoritative answers. I looked to see if I can find any authoritative sources that share my opinion. What I found was just a single other use of &quot;strong&quot; and &quot;weak&quot; in a programming context which feels consistent:</p>
<ol>
<li>A <a href="https://en.wikipedia.org/wiki/Weak_reference" rel="nofollow noreferrer">weak reference</a>, in languages/runtimes with automatic memory management, is one in whose existence does not protect the value from being freed or garbage collected. You could rephrase my claim as &quot;in a strongly typed language, the compiler or runtime protects the variable from being assigned a type-incompatible value.&quot; Therefore: &quot;strong&quot; implies some kind of protection, and &quot;weak&quot; implies a lack of said protection.</li>
<li>Nope, #1 is all I've got. <em>leaves quietly</em></li>
</ol>

CC BY-SA 4.0
2024-04-29T20:39:52.723Z
2024-04-30T18:28:03.923Z
2024-04-30T18:28:03.923Z
JakeRobb
CC BY-SA 4.0
2024-04-29T20:44:36.890Z
Welcome! Note that this question is asking for "authoritative" definitions ─ do you have a reference to show that this definition is used by researchers, language designers, etc.?
kaya3
CC BY-SA 4.0
2024-04-29T20:50:09.783Z
Ah, sorry, I missed that part of the question. I don't, but I'll look around and see if I can find anyone authoritative who agrees with me. 
JakeRobb
CC BY-SA 4.0
2024-04-29T21:06:57.823Z
I've edited with a very weak hint of authoritative support for my opinion. 
JakeRobb
CC BY-SA 4.0
2024-04-30T17:18:54.697Z
"A strongly typed language enforces that when a variable is declared, variable is assigned a type (explicitly or implicitly), and for the duration of the variable's lifecycle, it will continue to have that type and only that type. A weakly typed language doesn't do this." JavaScript enforces this property on *values*. If you have two variables that name the same array, then you can make one or the other name an integer instead, but you can't make them *simultaneously* name an integer by *transforming* the array into an integer.
Karl Knechtel
CC BY-SA 4.0
2024-04-30T17:38:18.620Z
@KarlKnechtel I don't follow. What does it mean for two variables to "name the same array"?
JakeRobb
CC BY-SA 4.0
2024-04-30T17:57:31.957Z
Exactly what it sounds like. JavaScript's variables are names - just like Python's, almost all of Java's, and certain of C#'s. They have *reference semantics*, meaning that assigning to them *does not* copy the thing that was assigned, but instead makes that variable function as another name for the thing (mechanically: an automatically-deferenced pointer - *not* like a C++ reference type, because assignment "reseats" the reference rather than passing through to an assignment operator on the type.)
Karl Knechtel
CC BY-SA 4.0
2024-04-30T18:22:37.330Z
okay, so you're saying `var a = [1,2,3]; var b = a;`, i.e. two references to the same item in memory? If so, then I think I get the point you're making, but I'm not sure how it's relevant. It feels some sort of zen thing, e.g. "Rain makes the ground wet." "Ah yes, but does it make the lake wet?" It's an interesting thing to think about, but it feels far outside the scope of the conversation.
JakeRobb
CC BY-SA 4.0
2024-06-10T12:58:00.363Z
Your example is more indicative of the difference between static and dynamic typing. Weak typing would mean you could add `123 + "456"` and (depending on the rules governing type conversions) get either `579` or `"123456"` as an answer, rather than a type error.
chepner
<p>The Wikipedia article, and the blog post, are correct that these terms are not well-defined and are not useful for communicating in general, and at best can be used in a relative way within a particular context. Sometimes they refer to accessing the bit representation of a value as another type, sometimes they are about implicit type coercions, sometimes they refer to polymorphism, sometimes they refer to the presence of static types at all, sometimes they are about expressivity or dependent properties like bounds checking, and sometimes they are just a subjective impression of quality (&quot;A type system that I like and feel comfortable with&quot;, indeed).</p>
<p>You will see these terms used with quietly different meanings, and you'll see those meanings explicitly disputed, sometimes both by what you might consider experts. That doesn't mean that they aren't used or can't be useful within narrow contexts where the relativity and the elements under comparison are understood and help, but it does suggest that they're not useful as freestanding terms.</p>
<p>I'm going to look at some uses of these terms from academic literature over time, and then highlight some conflicts that arise within it, both explicitly and implicitly.</p>
<hr />
<p>Firstly, let's try to look for an actual definition, and then see whether that tracks with usage.</p>
<p>The <em>Oxford Dictionary of Computer Science</em> <a href="https://www.oxfordreference.com/display/10.1093/acref/9780199688975.001.0001/acref-9780199688975-e-5115?rskey=Le0DZb&amp;result=1" rel="nofollow noreferrer">defines &quot;strong typing&quot;</a> as:</p>
<blockquote>
<p>A feature of some programming languages that requires the type of each data item to be declared, precludes the application of operators to inappropriate data types, and prevents the interaction of incompatible types.</p>
</blockquote>
<p>It does not have a definition for &quot;weak typing&quot;. This is probably the closest thing to an &quot;authoritative definition&quot; (at least, it's trying to be), but you might find points to question in there already, and many times the term is used will not be entirely consistent with it; it also depends on the meanings of several <em>other</em> terms, like &quot;type&quot;.</p>
<p>Strongly-, weakly-, and even statically- and dynamically-typed just are not as firmly-defined as people tend to think while they're using them. To highlight this I sometimes put forward the case that &quot;C is strongly-typed, Perl is statically-typed&quot;: both of these claims are <strong>obviously definitionally false</strong>, and yet... they seem to be true, from a certain point of view, under conventional descriptions of what those terms mean, and many definitions inadvertently include them.</p>
<hr />
<p>A historical wart here is also that &quot;strong typing&quot; and &quot;static typing&quot; have at times been used as essentially exact synonyms; for example, see this <a href="https://doi.org/10.1145/141936.290558" rel="nofollow noreferrer">Bertrand Meyer abstract from OOPSLA 1992, <em>Ensuring strong typing in an object-oriented language</em></a>:</p>
<blockquote>
<p>Static typing, also known as strong typing, has a long and rich history in programming languages.</p>
</blockquote>
<p>On the other hand, we can look to <a href="https://doi.org/10.1145/97945.97964" rel="nofollow noreferrer"><em>Strong typing of object-oriented languages revisited</em> from OOPSLA/ECOOP 1990</a>:</p>
<blockquote>
<p>We regard this as a continuum where <strong>weakly typed means that the type of an expression carries little or no information</strong>. Smalltalk is an example of such a language where the type of instance variables convey very little information on what messages are legal to send to the denoted object. A <strong>perfectly strongly typed language would exclusively have expressions where its type carries all information about the denoted object</strong>.
[...]
Languages with a hierarchical type system and qualified references serve as a compromise since some, but not necessarily all, operations on an object can be inferred from the qualification of the reference.</p>
</blockquote>
<p>So, here, typical object-oriented polymorphism is contrary to strong typing. Among users of functional languages, this is a common concept of strong typing.</p>
<p>Further back, <a href="https://doi.org/10.1145/988113.988117" rel="nofollow noreferrer"><em>Type equivalence in strongly typed languages: one more look</em> from 1979</a> says:</p>
<blockquote>
<p>In a strongly typed language, each value has a unique type. The key impact of this is that, starting with the knowledge of the type of each identifier and constant appearing in the program, it is possible to determine the type of every expression
in the program.</p>
</blockquote>
<p>This is more or less just a description of sound static typing. It <em>may</em> rule out polymorphism again, although the languages being discussed simply didn't have it and that probably wasn't in mind.</p>
<p>A direct, if handwaved, definition is given in <a href="https://doi-org.helicon.vuw.ac.nz/10.1145/3192366.3192388" rel="nofollow noreferrer">this paper</a>:</p>
<blockquote>
<p>Type systems may be static (compile time), dynamic (run time), strong (strict), or weak (loose). The type system of C/C++ is static and weak,
meaning that it is up to the programmer to prevent type errors from occurring at runtime</p>
</blockquote>
<p>followed by</p>
<blockquote>
<p>The C/C++ type system is intentionally weak, i.e., allowing for arbitrary pointer casting</p>
</blockquote>
<p>thus definining &quot;weak typing&quot; as memory reinterpretation. This is also a fairly conventional meaning for strong &amp; weak typing.</p>
<p>We can see discussion of the very conflict you bring up as well, such as in <a href="https://doi.org/10.5555/369279.369331" rel="nofollow noreferrer"><em>Assessing the ripple effect of CS1 language choice</em> in 2000</a>:</p>
<blockquote>
<p><strong>Some say that C++ is strongly typed but</strong> this statement should be taken only with respect to the default static typing done on calls made through base class pointers. <strong>Otherwise, C++ is weakly typed like C</strong>, full of implicit casts, the interpretation of any type as a boolean, and the treatment of all primitives as integers -- language constructs that fail to reinforce the notion of a type to a novice.</p>
</blockquote>
<p>We can see that there are some pretty divergent uses of &quot;strong&quot; and &quot;weak&quot; already. If these uses are sufficiently disjoint, maybe that would be ok.</p>
<hr />
<p>There are direct conflicts in the uses of the terms. Let's zoom in on just one language and see how it's been described. We can see <a href="https://doi.org/10.1145/3639061" rel="nofollow noreferrer">identification of Python as strongly-typed</a>:</p>
<blockquote>
<p>In contrast, using <strong>strongly typed text languages (even dynamically like
Python)</strong> requires the understanding of data types and the respect of languages grammar and syntax</p>
</blockquote>
<p>And we can see <a href="https://doi.org/10.1145/3486608.3486909" rel="nofollow noreferrer">identification of Python</a> as <a href="https://doi.org/10.1145/3458817.3476176" rel="nofollow noreferrer">not strongly-typed</a>:</p>
<blockquote>
<p>This is rather difficult to detect in Python due to the lack of strong typing, and as such, there are additional uses that are not included in the results</p>
</blockquote>
<blockquote>
<p>TensorFlow used Python’s weak typing system to construct graphs from Python functions</p>
</blockquote>
<p>We can see a set of languages classified as strongly- or weakly-typed in <a href="https://doi.org/10.1145/2635868.2635922" rel="nofollow noreferrer"><em>A Large Scale Study of Programming Languages and Code Quality in GitHub</em>, FSE 2014</a>:</p>
<div class="s-table-container"><table class="s-table">
<thead>
<tr>
<th>Strong</th>
<th>Weak</th>
</tr>
</thead>
<tbody>
<tr>
<td>C#, Java, Go, Python, Ruby, Clojure, Erlang, Haskell, Scala</td>
<td>C, C++, Objective-C, CoffeeScript, JavaScript, Perl, PHP</td>
</tr>
</tbody>
</table></div>
<p>Once more, Python is identified as strongly-typed. We can also <a href="https://wiki.python.org/moin/Why%20is%20Python%20a%20dynamic%20language%20and%20also%20a%20strongly%20typed%20language" rel="nofollow noreferrer">find</a> many <a href="https://news.ycombinator.com/item?id=17049499" rel="nofollow noreferrer">other</a> real-world <a href="https://www.linkedin.com/advice/0/what-difference-between-strongly-weakly-typed-eqwlc" rel="nofollow noreferrer">uses</a> that <a href="https://wiki.python.org/moin/StrongVsWeakTyping" rel="nofollow noreferrer">classify</a> it in both directions, give conflicting definitions, and argue quite intensely.</p>
<p>You might agree or disagree with some others of those listed languages as well — and you'll see <em>that</em> reflected in the literature as well, including directly in
<a href="https://doi.org/10.1145/3340571" rel="nofollow noreferrer"><em>On the Impact of Programming Languages on Code Quality: A Reproduction Study</em> in TOPLAS from Emery D. Berger, Celeste Hollenbeck, Petr Maj, Olga Vitek, Jan Vitek in 2019</a>:</p>
<blockquote>
<p>The Type category is the most counter-intuitive for programming language experts as it expresses whether a language allows
value of one type to be interpreted as another, e.g., due to automatic conversion.
The <a href="https://doi-org.helicon.vuw.ac.nz/10.1145/3126905" rel="nofollow noreferrer">CACM paper</a>
attempted to clarify this definition with the example of the ID type. In Objective-C, an ID variable
can hold any value. If this is what the authors intend, then <strong>Python, Ruby, Clojure, and Erlang
would be weak</strong> as they have similar generic types.</p>
</blockquote>
<p>The CACM paper referred to changes the name of that category to &quot;Implicit type conversion&quot;, so clarifying that as the meaning they intended by &quot;strong/weak typing&quot; the first time (and likely reflecting pushback in between on this very controversy over the terms!). This is <em>one</em> meaning of &quot;weak typing&quot;, but as we have seen above it's not the only one.</p>
<hr />
<p>JavaScript given there is one of the categorical examples of weak typing, used all over the place, because of <a href="https://262.ecma-international.org/#sec-applystringornumericbinaryoperator" rel="nofollow noreferrer">its many implicit coercions</a>. On the other hand, another conventional perspective is that weak typing is about reinterpreting a value's memory representation as another type — this is where C falls — and you definitely <em>can't</em> do that in JavaScript — is it strongly typed? On yet another hand, C does define some types that can't be reinterpreted that way (function pointers) so is it strongly-typed too? We are stretching the terms beyond meaning at this point, but it highlights where these handwaves don't hold up when pushed.</p>
<p>Even this perspective that it's the implicit coercions that make JavaScript weakly-typed isn't as particular as it seems on the surface.</p>
<ul>
<li>Is every language with implicit widening conversion from float to double then weakly-typed also? Java does that, and but is typically seen as strongly-typed.</li>
<li>Is it the sheer number of type coercions? Java and C# actually have <em>more</em>, because they have multiple numeric types.</li>
<li>Is it accessing methods or fields from different types through the same variable? This is just dynamic typing or polymorphism, so what's the role of &quot;weak&quot; here?</li>
<li>Is it automatically invoking a stringifying operation during string concatenation? Many of the supposedly strongly-typed languages given above do that too.</li>
<li>Is it that typical JavaScript code tends to invoke these coercions often? That doesn't have much to do with typing and is an empirical claim about usage, rather than the design of the language.</li>
<li>Is it converting from strings back to numbers? Now we're getting somewhere specific, but we've come a long way from &quot;is weakly-typed&quot; and could more usefully say that directly!</li>
</ul>
<p>On the other hand, in Perl there is no need for such a string⇒number conversion, because numbers and strings are the same type all along: is it then strongly-typed? Or perhaps all those other languages are weakly-typed too — but clearly that perspective is not universal, so we'd need to be explaining what we meant, and one wonders why we want to use these specific words for that.</p>
<p>Even other answers <em>to this question</em> pick out JavaScript as obviously without question <a href="https://langdev.stackexchange.com/a/3762/133">one</a> or the <a href="https://langdev.stackexchange.com/a/3761/133">other</a>. They give entirely contradictory rationales that let us distinguish the meanings in use, but clearly the terms then don't tell us anything themselves. We need to explain what properties we are concerned with, and then the explanation can stand on its own instead.</p>
<p>We can also look to <a href="https://langdev.stackexchange.com/questions/3741/how-are-strong-and-weak-typing-defined#comment11892_3741">Eric Lippert, a designer of C#, to comment on that language</a>:</p>
<blockquote>
<p>Well if I'm an authority then: I agree with Curtis. Is C# strongly typed? It has many features that people describe as &quot;strong&quot; and many features that people describe as &quot;weak&quot;. If you mean &quot;allows casting&quot;, say &quot;allows casting&quot;, not &quot;weak&quot;. If you mean &quot;objects can describe their types&quot; then say &quot;objects can describe their types&quot;, not &quot;strong&quot;.</p>
</blockquote>
<p>This is highlighting where these terms are not useful on their own: it would be better to say <em>what you actually mean</em> about the type system, rather than bundling it up into &quot;strong&quot; or &quot;weak&quot;, if you want to communicate something. Someone else will have a different meaning and a different understanding. The Python examples above highlight that it simply isn't useful to say &quot;strong typing&quot;: you need to say what you're actually talking about, or you'll be talking past one another.</p>
<hr />
<p>I wanted to sum up with a general high-level description of things that were suggestive of each category, but I'm not sure I can even do that. We might try to say that:</p>
<ul>
<li>A strongly-typed language is one where a value can only be used as its one true type — which could still be multiple types, or perhaps it can't, and what exactly is a type in this language, anyway?, and of course I want my language be strongly-typed and perhaps I don't want yours to be (witness the arguments about Python), and—</li>
<li>A weakly-typed language is one where the bits of a value can be reinterpreted as another type — or one where they can't, but there are &quot;too many&quot; coercions available, or the coercions that exist are too error-prone, or the <em>operations</em> that give me a value of one type given a value of another type aren't the right shape, or the <em>types</em> that exist aren't the sorts of types I want to think of as types, or—</li>
</ul>
<p>We can see a pattern there that &quot;weak typing&quot; is mostly negative framing, and I think that brings us back around to the quote from your question:</p>
<blockquote>
<ul>
<li>Strong typing: A type system that I like and feel comfortable with</li>
<li>Weak typing: A type system that worries me, or makes me feel uncomfortable</li>
</ul>
</blockquote>
<p>Yes, that seems about right for how people use those terms. <em>In context</em>, it can make sense to contrast different approaches in that way, with a particular value system as a frame of reference, but in the abstract &quot;strong typing&quot; and &quot;weak typing&quot; don't communicate much more.</p>

CC BY-SA 4.0
2024-04-27T23:33:51.487Z
2024-06-10T02:03:25.180Z
2024-06-10T02:03:25.180Z
Michael Homer
CC BY-SA 4.0
2024-04-28T00:05:55.577Z
This is an excellent answer, thank you. One thing: where you say *"This is more or less just a description of sound static typing"*, that definition requires *"each value has a unique type"*, where "unique" taken literally would imply that subtypes and supertypes don't exist in the language (otherwise a value of a subtype would also have the supertype as one of its types). That's much more restrictive than strong static typing (few languages have no subtypes ─ Rust is close, but references can have subtypes with different lifetimes), but I guess that definition is not intended that way.
kaya3
CC BY-SA 4.0
2024-04-28T07:12:14.973Z
I have seen a definition of *strong**er*** typing (i.e., a partial order on languages), where language A is considered to be *more strongly typed* than language B, IFF language A's type system rejects a program that language B's accepts. However, considering the psychological aspect you highlighted in your last paragraph, that means that, of course, everybody wants their favorite language to be *stronger* than everybody else's favorite language. The problem is, with this definition, the strongest typed language is the one whose compiler just looks like `def compile(p) = throw TypeError`.
Jörg W Mittag
CC BY-SA 4.0
2024-04-28T13:00:06.057Z
@JörgWMittag actually that's a pretty good point deserving a mention in this answer if not an answer of it's own: it's a lot easier to justify a relative ordering (e.g. Haskell is more strongly typed than Javascript) than a binary classification. I don't know if that's enough to salvage terms that are otherwise fraught with peril, but there is that.
Jared Smith
CC BY-SA 4.0
2024-04-28T18:12:26.333Z
@JaredSmith That sort of relativity is through the answer, but in reality that formal test is very rarely going to be a partial order — “rejects additional program” just isn’t going to be mutually consistent other than for small extensions to one language. I don’t think that property is useful for distant languages, just a way of saying “*this* change to *this* type system makes it more restrictive”. You can easily have different programs rejected by both sides, and what then? “Stronger” is more useful, but only because you can have a shared value system and frame of reference of the original.
Michael Homer
CC BY-SA 4.0
2024-06-12T13:27:59.420Z
I'm noticing that we're calling C/C++'s reinterpret casting a source of "weak" typing, but then calling C# more strongly typed despite allowing something similar in unsafe context.  For example Quake's inverse square root "Evil bit hack" compiles and runs in C# if it's defined as unsafe.  I'm pointing this out just because I'm guessing that for many languages there are features that might not get considered in analyzing weak vs strong because they're uncommonly used.
IllusiveBrian
CC BY-SA 4.0
2024-06-12T19:08:29.320Z
@IllusiveBrian I don’t think we’re calling anything anything, precisely because the terms don’t have enough meaning even to say what contributes to them!
Michael Homer
CC BY-SA 4.0
2024-06-12T19:21:39.800Z
@MichaelHomer Sorry you're right, I was referring to the chart in the answer.
IllusiveBrian
# How are "strong" and "weak" typing defined?
Posted by: username_0 on 2024-04-27
According to [Wikipedia](https://en.wikipedia.org/wiki/Strong_and_weak_typing), the terms "strongly typed" and "weakly typed" do not have agreed-upon formal definitions:

> there is no precise technical definition of what the terms mean and different authors disagree about the implied meaning of the terms and the relative rankings of the "strength" of the type systems of mainstream programming languages.

Wikipedia cites [a 2010 blog post](https://blogs.perl.org/users/ovid/2010/08/what-to-know-before-debating-type-systems.html) by [Curtis Poe](https://ovid.github.io/) for this claim, but the blog post doesn't cite any sources itself, and is written in a quite opinionated way (emphasis in original):

> Probably the most common way type systems are classified is "strong" or "weak." This is unfortunate, since these words have nearly no meaning at all. It is, to a limited extent, possible to compare two languages with very similar type systems, and designate one as having the strong**er** of those two systems. Beyond that, the words mean nothing at all.
>
> Therefore: I give the following general definitions for strong and weak typing, at least when used as absolutes:
>
> * **Strong typing:** A type system that I like and feel comfortable with
> * **Weak typing:** A type system that worries me, or makes me feel uncomfortable

Given the age and informality of the source, is this claim true? What **authoritative** definitions are there for "strong" and "weak" typing, and is there disagreement on these terms between different authorities?

---

To clarify what counts as "authoritative", see Wikipedia's rules for [reliable sources](https://en.wikipedia.org/wiki/Wikipedia:Reliable_sources) (also [here](https://en.wikipedia.org/wiki/Wikipedia:Verifiability#Reliable_sources)):

> If available, academic and peer-reviewed publications are usually the most reliable sources on topics such as [...] science. [...] Other reliable sources include:
>
> * University-level textbooks
> * Books published by respected publishing houses
> * Mainstream (non-fringe) magazines, including specialty ones

> Self-published expert sources may be considered reliable when produced by an established expert on the subject matter, whose work in the relevant field has previously been published by reliable, independent publications.

Wikipedia's article does refer to some definitions from academic literature, but these seem to describe static typing and type safety, which are usually considered distinct concepts to strong typing.
**Tags:** types terminology
> **Comments:**
> **username_1**: See the related Wikipedia article on [type safety](https://en.wikipedia.org/wiki/Type_safety#Strong_and_weak_typing).  In particular one aspect of type safety is [compile-time type checking](https://stackoverflow.com/questions/260626/what-is-type-safe) and c.f. related posts at StackOverflow.  
> **username_2**: I would guess that most programming languages textbooks would contain a definition or at least some sort of discussion.  Starting point: [*The Structure of Typed Programming Languages* by David A. Schmidt](https://www.google.com/books/edition/The_Structure_of_Typed_Programming_Langu/Ax2QXEwXhzQC?hl=en&gbpv=1&dq=strongly%20typed&pg=PA6&printsec=frontcover) "A language with static typing is *strongly typed* if no well-typed program produces run-time incompatibility errors."  
> **username_0**: @NateEldredge This seems to describe what we normally call type safety or soundness, and doesn't tell us what it means for a dynamically-typed language. If there are no reliable sources which distinguish between strength and safety/soundness, though, then an answer which establishes that would also be good.  
> **username_3**: I wonder if there is some distinction where you can have dynamically typed languages that are *technically* type safe (because the way the error messages work are fully defined) in contrast to languages where type errors produce runtime behavior which cannot really be (fully) defined (such as potential segfaults).  
> **username_4**: I think there is a real difficulty with this question because the premise *is* true — there isn’t an established, agreed definition, so “authoritative” sources either don’t define it (because the definition would be wrong sometimes) or use a local definition that is inconsistent with others. On the other hand, people do use those terms with locally-consistent meaning. Is an answer just a survey of different publications and how they use it?  
> **username_0**: @MichaelHomer A survey of how the term is defined (or at least used) in different publications would be good; even better with some analysis of how they agree or disagree on the term's meaning.  
> **username_3**: It would also be interesting to see where there might be agreement in the different definitions. For instance, I'd be pretty surprised to see any definition where C is "strongly typed."  
> **username_5**: Well if I'm an authority then: I agree with Curtis. Is C# strongly typed? It has many features that people describe as "strong" and many features that people describe as "weak".  If you mean "allows casting", say "allows casting", not "weak".  If you mean "objects can describe their types" then say "objects can describe their types", not "strong".  
> **username_0**: @EricLippert Curtis's post seemed to me a bit too polemic to be an accurate reflection of how the terms would be used by experts, but if the reason they lack formal definitions is because experts don't find the terms to be useful, then perhaps I should take his post more literally. If there is evidence that experts in general avoid these terms for that reason then that would make a great answer, and perhaps convince more people to stop using them in favour of clearer descriptors.  
> **username_6**: Found [What does weak static typing/strong dynamic typing mean?](https://softwareengineering.stackexchange.com/q/297653/439060) on the Software Engineering stack. One answer does contain ``It makes a "great" argument in a flamewar`` about asking for the meaning of _strongly typed_ and _weakly typed_.  
> **username_0**: @ChesterGillon Good find; especially the quote by Benjamin Pierce. The source for that quote seems to be [a Reddit comment](https://www.reddit.com/r/programming/comments/t7v9/comment/ct8je/) by Mark Jason Dominus.  
> **username_7**: "Weak" means a type system that the person you're talking to doesn't like. ;-)  
> **username_8**: First we need to understand, *what is a type*. A type is *a set of possible values*. For example, `uint16_t` in C has a very clearly defined, not very big set. Other types are more hard to define, but what we always find, that is *the set of values*. That is the idealistic part of this post. In this sense, we can talk about "typed" and about "typeless" languages, as two extremes. In practice, in the engineering practice, these are only ideas and the real programming languages stay somewhere between these extremes. We can call "weakly typed" the languages more close to the typeless langs.  
> **username_0**: @peterh I've long thought that "a set of possible values" is one view of what a type is, but not a complete view. In TypeScript for example `{x: number} | {x: string}` is not the same type as `{x: number | string}` despite the two value sets being the same. And once you start considering generics, two function types might end up having the same set of values, e.g. `() => []` is (essentially) the only value of type `() => []` but also the only value of type `<T>() => T[]`, and the only value of type `<T extends Foo>() => T[]`.  
> **username_9**: It's really a sliding scale that depends on how much the language implicitly converts types. Perl is on the weak end, Haskell is on the strong end, and C is somewhere in the middle. Where exactly a person might draw the line between weak and strong typing comes down to preference.  
> **username_0**: @Beefster I'm aware of the popular definition that strength/weakness is about implicit conversions (aka coercion); this is also already covered in the accepted answer. The question is about authoritative definitions, so if you have an authoritative source for this definition then that would be relevant.  
> **username_8**: @kaya3 I think we should differentiate between type as the element of a set, and type as the language defines it. Even if TypeScript has this... *nuance*... you still can say of "anything" if it is a `number | string` or not. Also generics, function types don't change it. You still can say from everything, if it is one of not. Question if, how important is it for the language, is that thing an element of that set or not.  
> **username_3**: @peterh That distinction between types and sets actually [runs quite a bit deeper than just "language quirks"](https://cs.stackexchange.com/a/91345/20578).  
> **username_0**: @peterh I don't think this is at all a quirk of TypeScript. Consider two classes like `final class Foo { private Foo() { throw new RuntimeException(); } }` and `Bar` defined similarly in Java; the types `Foo` and `Bar` admit only the value `null`, but they are not the same type. Also consider type erasure: technically in Java every value of type `List<String>` could be held by a variable of type `List<Integer>` and vice versa, via casts using the bare type `List`; but of course they are not the same type.  
> **username_0**: In general, you may use any valid mathematical proof to show that two sets are equal; but a type system defines a much more limited set of rules, and types are only equivalent in that system if they can be proved using those rules.  
> **username_8**: @DavidYoung Wow, right :-) I am thinking, thanks the link.  
---
## 4 answers
### Answer by username_4 on 2024-04-27. Score: 31 | Accepted answer
The Wikipedia article, and the blog post, are correct that these terms are not well-defined and are not useful for communicating in general, and at best can be used in a relative way within a particular context. Sometimes they refer to accessing the bit representation of a value as another type, sometimes they are about implicit type coercions, sometimes they refer to polymorphism, sometimes they refer to the presence of static types at all, sometimes they are about expressivity or dependent properties like bounds checking, and sometimes they are just a subjective impression of quality ("A type system that I like and feel comfortable with", indeed).

You will see these terms used with quietly different meanings, and you'll see those meanings explicitly disputed, sometimes both by what you might consider experts. That doesn't mean that they aren't used or can't be useful within narrow contexts where the relativity and the elements under comparison are understood and help, but it does suggest that they're not useful as freestanding terms.

I'm going to look at some uses of these terms from academic literature over time, and then highlight some conflicts that arise within it, both explicitly and implicitly.

---

Firstly, let's try to look for an actual definition, and then see whether that tracks with usage.

The *Oxford Dictionary of Computer Science* [defines "strong typing"](https://www.oxfordreference.com/display/10.1093/acref/9780199688975.001.0001/acref-9780199688975-e-5115?rskey=Le0DZb&result=1) as:

> A feature of some programming languages that requires the type of each data item to be declared, precludes the application of operators to inappropriate data types, and prevents the interaction of incompatible types.

It does not have a definition for "weak typing". This is probably the closest thing to an "authoritative definition" (at least, it's trying to be), but you might find points to question in there already, and many times the term is used will not be entirely consistent with it; it also depends on the meanings of several *other* terms, like "type".

Strongly-, weakly-, and even statically- and dynamically-typed just are not as firmly-defined as people tend to think while they're using them. To highlight this I sometimes put forward the case that "C is strongly-typed, Perl is statically-typed": both of these claims are **obviously definitionally false**, and yet... they seem to be true, from a certain point of view, under conventional descriptions of what those terms mean, and many definitions inadvertently include them.

---

A historical wart here is also that "strong typing" and "static typing" have at times been used as essentially exact synonyms; for example, see this [Bertrand Meyer abstract from OOPSLA 1992, *Ensuring strong typing in an object-oriented language*](https://doi.org/10.1145/141936.290558):

> Static typing, also known as strong typing, has a long and rich history in programming languages.

On the other hand, we can look to [*Strong typing of object-oriented languages revisited* from OOPSLA/ECOOP 1990](https://doi.org/10.1145/97945.97964):

> We regard this as a continuum where **weakly typed means that the type of an expression carries little or no information**. Smalltalk is an example of such a language where the type of instance variables convey very little information on what messages are legal to send to the denoted object. A **perfectly strongly typed language would exclusively have expressions where its type carries all information about the denoted object**.
> [...]
> Languages with a hierarchical type system and qualified references serve as a compromise since some, but not necessarily all, operations on an object can be inferred from the qualification of the reference.

So, here, typical object-oriented polymorphism is contrary to strong typing. Among users of functional languages, this is a common concept of strong typing.

Further back, [*Type equivalence in strongly typed languages: one more look* from 1979](https://doi.org/10.1145/988113.988117) says:

> In a strongly typed language, each value has a unique type. The key impact of this is that, starting with the knowledge of the type of each identifier and constant appearing in the program, it is possible to determine the type of every expression
> in the program.

This is more or less just a description of sound static typing. It *may* rule out polymorphism again, although the languages being discussed simply didn't have it and that probably wasn't in mind.

A direct, if handwaved, definition is given in [this paper](https://doi-org.helicon.vuw.ac.nz/10.1145/3192366.3192388):

> Type systems may be static (compile time), dynamic (run time), strong (strict), or weak (loose). The type system of C/C++ is static and weak,
> meaning that it is up to the programmer to prevent type errors from occurring at runtime

followed by

> The C/C++ type system is intentionally weak, i.e., allowing for arbitrary pointer casting

thus definining "weak typing" as memory reinterpretation. This is also a fairly conventional meaning for strong & weak typing.

We can see discussion of the very conflict you bring up as well, such as in [*Assessing the ripple effect of CS1 language choice* in 2000](https://doi.org/10.5555/369279.369331):

> **Some say that C++ is strongly typed but** this statement should be taken only with respect to the default static typing done on calls made through base class pointers. **Otherwise, C++ is weakly typed like C**, full of implicit casts, the interpretation of any type as a boolean, and the treatment of all primitives as integers -- language constructs that fail to reinforce the notion of a type to a novice.

We can see that there are some pretty divergent uses of "strong" and "weak" already. If these uses are sufficiently disjoint, maybe that would be ok.

---

There are direct conflicts in the uses of the terms. Let's zoom in on just one language and see how it's been described. We can see [identification of Python as strongly-typed](https://doi.org/10.1145/3639061):

> In contrast, using **strongly typed text languages (even dynamically like
> Python)** requires the understanding of data types and the respect of languages grammar and syntax

And we can see [identification of Python](https://doi.org/10.1145/3486608.3486909) as [not strongly-typed](https://doi.org/10.1145/3458817.3476176):

> This is rather difficult to detect in Python due to the lack of strong typing, and as such, there are additional uses that are not included in the results

> TensorFlow used Python’s weak typing system to construct graphs from Python functions

We can see a set of languages classified as strongly- or weakly-typed in [*A Large Scale Study of Programming Languages and Code Quality in GitHub*, FSE 2014](https://doi.org/10.1145/2635868.2635922):

| Strong | Weak |
| --- | --- |
| C#, Java, Go, Python, Ruby, Clojure, Erlang, Haskell, Scala | C, C++, Objective-C, CoffeeScript, JavaScript, Perl, PHP |

Once more, Python is identified as strongly-typed. We can also [find](https://wiki.python.org/moin/Why%20is%20Python%20a%20dynamic%20language%20and%20also%20a%20strongly%20typed%20language) many [other](https://news.ycombinator.com/item?id=17049499) real-world [uses](https://www.linkedin.com/advice/0/what-difference-between-strongly-weakly-typed-eqwlc) that [classify](https://wiki.python.org/moin/StrongVsWeakTyping) it in both directions, give conflicting definitions, and argue quite intensely.

You might agree or disagree with some others of those listed languages as well — and you'll see *that* reflected in the literature as well, including directly in
[*On the Impact of Programming Languages on Code Quality: A Reproduction Study* in TOPLAS from Emery D. Berger, Celeste Hollenbeck, Petr Maj, Olga Vitek, Jan Vitek in 2019](https://doi.org/10.1145/3340571):

> The Type category is the most counter-intuitive for programming language experts as it expresses whether a language allows
> value of one type to be interpreted as another, e.g., due to automatic conversion.
> The [CACM paper](https://doi-org.helicon.vuw.ac.nz/10.1145/3126905)
> attempted to clarify this definition with the example of the ID type. In Objective-C, an ID variable
> can hold any value. If this is what the authors intend, then **Python, Ruby, Clojure, and Erlang
> would be weak** as they have similar generic types.

The CACM paper referred to changes the name of that category to "Implicit type conversion", so clarifying that as the meaning they intended by "strong/weak typing" the first time (and likely reflecting pushback in between on this very controversy over the terms!). This is *one* meaning of "weak typing", but as we have seen above it's not the only one.

---

JavaScript given there is one of the categorical examples of weak typing, used all over the place, because of [its many implicit coercions](https://262.ecma-international.org/#sec-applystringornumericbinaryoperator). On the other hand, another conventional perspective is that weak typing is about reinterpreting a value's memory representation as another type — this is where C falls — and you definitely *can't* do that in JavaScript — is it strongly typed? On yet another hand, C does define some types that can't be reinterpreted that way (function pointers) so is it strongly-typed too? We are stretching the terms beyond meaning at this point, but it highlights where these handwaves don't hold up when pushed.

Even this perspective that it's the implicit coercions that make JavaScript weakly-typed isn't as particular as it seems on the surface.

* Is every language with implicit widening conversion from float to double then weakly-typed also? Java does that, and but is typically seen as strongly-typed.
* Is it the sheer number of type coercions? Java and C# actually have *more*, because they have multiple numeric types.
* Is it accessing methods or fields from different types through the same variable? This is just dynamic typing or polymorphism, so what's the role of "weak" here?
* Is it automatically invoking a stringifying operation during string concatenation? Many of the supposedly strongly-typed languages given above do that too.
* Is it that typical JavaScript code tends to invoke these coercions often? That doesn't have much to do with typing and is an empirical claim about usage, rather than the design of the language.
* Is it converting from strings back to numbers? Now we're getting somewhere specific, but we've come a long way from "is weakly-typed" and could more usefully say that directly!

On the other hand, in Perl there is no need for such a string⇒number conversion, because numbers and strings are the same type all along: is it then strongly-typed? Or perhaps all those other languages are weakly-typed too — but clearly that perspective is not universal, so we'd need to be explaining what we meant, and one wonders why we want to use these specific words for that.

Even other answers *to this question* pick out JavaScript as obviously without question [one](https://langdev.stackexchange.com/a/3762/133) or the [other](https://langdev.stackexchange.com/a/3761/133). They give entirely contradictory rationales that let us distinguish the meanings in use, but clearly the terms then don't tell us anything themselves. We need to explain what properties we are concerned with, and then the explanation can stand on its own instead.

We can also look to [Eric Lippert, a designer of C#, to comment on that language](https://langdev.stackexchange.com/questions/3741/how-are-strong-and-weak-typing-defined#comment11892_3741):

> Well if I'm an authority then: I agree with Curtis. Is C# strongly typed? It has many features that people describe as "strong" and many features that people describe as "weak". If you mean "allows casting", say "allows casting", not "weak". If you mean "objects can describe their types" then say "objects can describe their types", not "strong".

This is highlighting where these terms are not useful on their own: it would be better to say *what you actually mean* about the type system, rather than bundling it up into "strong" or "weak", if you want to communicate something. Someone else will have a different meaning and a different understanding. The Python examples above highlight that it simply isn't useful to say "strong typing": you need to say what you're actually talking about, or you'll be talking past one another.

---

I wanted to sum up with a general high-level description of things that were suggestive of each category, but I'm not sure I can even do that. We might try to say that:

* A strongly-typed language is one where a value can only be used as its one true type — which could still be multiple types, or perhaps it can't, and what exactly is a type in this language, anyway?, and of course I want my language be strongly-typed and perhaps I don't want yours to be (witness the arguments about Python), and—
* A weakly-typed language is one where the bits of a value can be reinterpreted as another type — or one where they can't, but there are "too many" coercions available, or the coercions that exist are too error-prone, or the *operations* that give me a value of one type given a value of another type aren't the right shape, or the *types* that exist aren't the sorts of types I want to think of as types, or—

We can see a pattern there that "weak typing" is mostly negative framing, and I think that brings us back around to the quote from your question:

> * Strong typing: A type system that I like and feel comfortable with
> * Weak typing: A type system that worries me, or makes me feel uncomfortable

Yes, that seems about right for how people use those terms. *In context*, it can make sense to contrast different approaches in that way, with a particular value system as a frame of reference, but in the abstract "strong typing" and "weak typing" don't communicate much more.
> **Comments:**
> **username_0** (2024-04-28): This is an excellent answer, thank you. One thing: where you say *"This is more or less just a description of sound static typing"*, that definition requires *"each value has a unique type"*, where "unique" taken literally would imply that subtypes and supertypes don't exist in the language (otherwise a value of a subtype would also have the supertype as one of its types). That's much more restrictive than strong static typing (few languages have no subtypes ─ Rust is close, but references can have subtypes with different lifetimes), but I guess that definition is not intended that way.  
> **username_17** (2024-04-28): I have seen a definition of *strong**er*** typing (i.e., a partial order on languages), where language A is considered to be *more strongly typed* than language B, IFF language A's type system rejects a program that language B's accepts. However, considering the psychological aspect you highlighted in your last paragraph, that means that, of course, everybody wants their favorite language to be *stronger* than everybody else's favorite language. The problem is, with this definition, the strongest typed language is the one whose compiler just looks like `def compile(p) = throw TypeError`.  
> **username_18** (2024-04-28): @JörgWMittag actually that's a pretty good point deserving a mention in this answer if not an answer of it's own: it's a lot easier to justify a relative ordering (e.g. Haskell is more strongly typed than Javascript) than a binary classification. I don't know if that's enough to salvage terms that are otherwise fraught with peril, but there is that.  
> **username_4** (2024-04-28): @JaredSmith That sort of relativity is through the answer, but in reality that formal test is very rarely going to be a partial order — “rejects additional program” just isn’t going to be mutually consistent other than for small extensions to one language. I don’t think that property is useful for distant languages, just a way of saying “*this* change to *this* type system makes it more restrictive”. You can easily have different programs rejected by both sides, and what then? “Stronger” is more useful, but only because you can have a shared value system and frame of reference of the original.  
> **username_19** (2024-06-12): I'm noticing that we're calling C/C++'s reinterpret casting a source of "weak" typing, but then calling C# more strongly typed despite allowing something similar in unsafe context.  For example Quake's inverse square root "Evil bit hack" compiles and runs in C# if it's defined as unsafe.  I'm pointing this out just because I'm guessing that for many languages there are features that might not get considered in analyzing weak vs strong because they're uncommonly used.  
> **username_4** (2024-06-12): @IllusiveBrian I don’t think we’re calling anything anything, precisely because the terms don’t have enough meaning even to say what contributes to them!  
> **username_19** (2024-06-12): @MichaelHomer Sorry you're right, I was referring to the chart in the answer.  
---
### Answer by username_10 on 2024-04-29. Score: 6
I recommend [Michael Homer's answer](https://langdev.stackexchange.com/a/3742/5222), though I would like to offer a definition of these terms I learned in university (circa 2017) that I find sensible.

Essentially, a "weakly typed" programming language is one **in which there exists one or more ways, within the language's spec, to circumvent its type system and ~~cause undefined behavior~~ break code the relies on its assumptions, requiring analysis at a lower level to understand it.** (**EDIT:** TypeScript presents an interesting caveat that forces me to generalize this definition - see below.) A "strongly typed" programming language is simply defined as having no such holes - the type system, no matter what it is, follows its stated rules.

Note that this is distinct from "static typing" vs. "dynamic typing", which are better defined. A **statically typed** language is one in which the types of its values can be determined at compile time, usually accompanied by an explicit requirement to declare the types of local/global variables, function arguments, and return values. In a **dynamically typed** language, the type information is handled internally within the variables at runtime, with the language not concerning itself with the value's type until it's necessary to do so.

JavaScript, for instance, is dynamically but strongly typed. Variable types are kept internally and there's no way to declare which ones are what (and you can end up with variables with the wrong type at runtime), but the type system has well defined rules for all eventualities - as long as no FFI code is involved, you can follow the code from the beginning, where each and every variable is instantiated, and use the language rules to know exactly what that code is going to do. Yes, you get an error if you try to call a method that doesn't exist on an object, but because the JavaScript runtime has exact rules on what happens when you look up a property that doesn't exist (getting the special value `undefined`) and what happens when you run the call operator on a value (such as `undefined`) that doesn't support it (you get a `TypeError`), the type system is still strong.

Contrast that with C, which is statically but weakly typed. All variables have a specific type associated with them, which you have to declare (unless you're using a variant that lets you use `auto` to declare a variable if its type can be exactly inferred from the incoming expression). Most expressions have specific rules for what types can be used together and when type casts occur (including implicit type casts). However, because dereferencing an invalid pointer value causes undefined behavior, and *arbitrary integers can be bit-cast to pointers* (including invalid ones), it is possible to circumvent C's type system - hence, C is weakly typed.

Rust is an interesting case - safe Rust (barring any design flaws) is strongly and statically typed, while unsafe Rust is weakly and statically typed. In both cases, the type system has well-defined rules (including rules with lifetimes, which are part of the value types for each variable and expression), but in unsafe Rust, some actions that break the type system and cause undefined behavior are possible, and it is up to the programmer to ensure that they are keeping the well-defined rules within the confines of the `unsafe` blocks.

On this note, I would not consider implicit type coercion to be an example of a weak type system, as long as the rules themselves for when this occurs are well defined. For instance, the language might go "oh, look at me! I'm going to cast this int to a float without telling you!" but as long as it defines *why* it thinks it's OK to cast the int to a float, and how exactly it's going to go about it, it's still well defined. Direct bit casting, as well, is not reason enough to declare a type system weak as long as 1) the values you're casting *to* and *from* have well-defined bit patterns, and 2) the value you're casting to doesn't have any invalid values (or the language at least has a well-defined rule for how to deal with these invalid values). I would not consider using silent failure values (e.g. using `NaN` for floating point errors, using `undefined` for missing a property lookup) to be indicative of a weak type system either, as long as the language has well-defined rules for when those error values appear and how those error values behave.

And this brings me to my last point: nothing about the "strength" or "weakness" of a type system, under this definition, has anything to do with what the programmer might want out of a type system. I would definitely argue that implicit casts, reckless reinterpret casting, and silent failure values are *bad*, but that opinion is ultimately subjective - some other programmer, at some other time, wanted those features in their language and defined rules for how they should work. Rather, the primary meaning of the strength or weakness of a type system, under this definition, **is its ability for a program written under that type system to reliably undergo a security audit.** Regardless of what the actual rules for the type system are, and whether you actually want to use them, if you can at least use the type system to reliably predict what a program is going to do given specific inputs (because none of the rules of the type system can be broken by other parts of the program), then it's a strong type system. A weak type system cannot reliably undergo such an audit, and programs must instead be analyzed at a lower level (i.e. debugging at the assembly code level on the target machine) to figure out what it's doing when it's not behaving properly.

**ADDENDUM:** Some other examples:

* Lambda calculus is statically and strongly typed, even though it doesn't have any type declarations (and is often considered "typeless"). This is because every single value has the same type: a function that takes one argument and returns one value (each of which is also a function that takes one argument and returns one value, and so on). The only allowed operations on these values are either calling them or composing them, which makes sense for these kinds of values.
* Python is dynamically and strongly typed for much the same reasons as JavaScript - again, as long as no FFI code is involved, you can follow the code from the beginning and determine which values are what type, even though the language does not enforce these in the syntax.
* Assembly code is dynamically typed, in that everything is just a set of bits and is treated as a particular kind of value upon running a specific instruction. Whether or not it's strongly or weakly typed is going to depend on the system it's running on top of, as that's where most of the actual definition of the assembly code comes from (though I think it'd be fair to call assembly language weakly typed on pretty much any platform, since system calls/interrupt vectors have different types, and there's probably at least one address that leads to invalid, undefined behavior when read to or written from from an arbitrarily constructed pointer).
* TypeScript presents an extremely interesting case: by this definition, it is actually *weakly* typed while JavaScript is strongly typed, paradoxically enough. This is because TypeScript, while providing incredible and flexible static type specifications with structural types/algebraic types/true top and bottom types, lets developers lie about all of this through type assertions, and must descend to a lower layer to understand the program when this happens. However, since JavaScript is strongly (although dynamically) typed, you only have to descend to that level, while a type-circumvented C program requires descending to assembly or further.
> **Comments:**
> **username_0** (2024-04-29): Welcome! The definition in your second paragraph looks like what we would normally call "[memory safety](https://en.wikipedia.org/wiki/Memory_safety)" - if there is a source for this as a definition of strong typing (e.g. your professor's lecture slides) it would help to add a link. Also, your first paragraph suggests you learned more than one definition in university, but I don't see any others (though you refer to coercion as *not* a definition).  
> **username_10** (2024-04-29): @kaya3 I'll see what I can find - it was forever ago. By "some definitions", I meant to imply "a definition each for strong, weak, static, and dynamic" - I'll change it to "a definition" since those definitions are linked.  
> **username_0** (2024-04-29): Fair enough. I think the edit makes this clearer.  
> **username_11** (2024-04-29): Minor quibble: in JavaScript, you can create a variable, assign it a value, and then assign it another value, and the types of the two values need not be compatible. In my mind, this makes JS weakly typed, as it enforces nothing about the type of the variable.  
> **username_10** (2024-04-29): @JakeRobb That's correct, and it does disqualify JS from being statically typed. I would not consider it weakly typed, however, since JavaScript has well-defined rules of how reassigning a variable with another value of a different type is supposed to work (since it looks at the type of the actual value at runtime and enforces its rules from there). It wouldn't be any different from having a Java variable of type `java.lang.Object`, for example.  
> **username_11** (2024-04-29): I can't think of any languages that don't care about the type of a _value_; leaning toward that not being possible. My point is about caring about the type of a _variable_ (i.e. the value's container). If you have a Java variable of type `j.l.Object`, you do need to assign it a value consistent with that type. Since Java 1.5 we have autoboxing (a limited form of compile-time type coercion), which makes it semantically impossible to violate that rule, but in the old days you could try to do it, and Java's strong typing compiler prevented you from doing so.  
> **username_3** (2024-04-29): @JakeRobb Forth does not care about types in any way, as far as I know. Assembly languages tend to be typeless. The untyped lambda calculus is typeless (appropriately enough).  
> **username_11** (2024-04-29): Assembly language types are generally just chunks of bits -- byte, word, etc. If I'm not mistaken, some modern processors do enforce that you're not passing, say, a memory address in when a value is expected....  
> **username_10** (2024-04-29): @JakeRobb re: Java - what I meant to convey is that JavaScript's type system is basically equivalent to having a Java program where _every single variable_ is declared as `Object`. It's possible to store any type of value in such a variable (either through direct storage or autoboxing), but the language would not let you call any method more specific than the Object base methods without some amount of runtime type checking or runtime reflection (such as looking up methods by string name, which is exactly what JavaScript does).  
> **username_11** (2024-04-29): I guess I see what you're saying, but conflating direct storage with autoboxing misses my point entirely. Java only demonstrates the difference if you acknowledge that autoboxing is a thing. You can't store a primitive in an Object, because Java doesn't let you, and that's what I claim is the key behavior of a strongly typed language (although I can find no authoritative source to support me on that).  
> **username_10** (2024-04-29): @JakeRobb That is a fair point, and I would consider that an example of both strong and static typing in Java - if you have a JVM `a` (reference) type, for instance, it's guaranteed to either be `null` or a pointer to a valid object, not just some random mishmash of bits that we're interpreting that way. I would just argue that if we had a version of Java where the primitive/reference distinction did not exist (i.e. everything lives in a boxed reference) and all variables are declared as `Object`, the language would still be strongly typed, just not statically typed.  
> **username_12** (2024-04-30): The same "unsafe" distinction appears in C#. At least, to the best of my understanding, it works essentially the same way in Rust that it does in C#.  
> **username_9** (2024-04-30): I don't think reinterpret casts inherently make a type system weak. That's a perfectly reasonable and well-defined behavior, albeit one that depends on the internal bit representation. I think the main aspect of C that makes its type system "weak" is that pointer conversions are implicit and silent. Contrast to something like Zig or Odin, which allows reinterpret casts, but only explicitly. Perl and Javascript both do a lot of implicit conversions between numbers and strings, leading to lots of surprises even though the behavior is well-defined.  
> **username_10** (2024-04-30): @Beefster Agreed. As I say further down in my post, I think that reinterpret casting creates a weak type system if and only if you are able to cast a _valid_ value from the source type into an _invalid_ value for the destination type, such that the language does not define what happens if you use the invalid value. The silent implicit conversions are definitely _bad_, and a language that requires explicit conversions is better, but Perl and JavaScript's implicit conversions aren't going to make demons fly out your nose.  
> **username_13** (2024-04-30): C is statically typed if one ignores type-based aliasing analysis.  The Standard's rules for TBAA, however, assume dynamic typing in ways that yield unworkable corner cases.  
---
### Answer by username_6 on 2024-04-28. Score: 2
The AdaCore [Strong Typing](https://learn.adacore.com/courses/Ada_For_The_CPP_Java_Developer/chapters/05_Type_System.html#strong-typing) section of [Ada for the C++ or Java Developer](https://learn.adacore.com/courses/Ada_For_The_CPP_Java_Developer/index.html) starts with (emphasis mine):

> One of the main characteristics of Ada is its strong typing (i.e., **relative** absence of implicit type conversions). This may take some getting used to. For example, you can't divide an integer by a float. You need to perform the division operation using values of the same type, so one value must be **explicitly converted** to match the type of the other (in this case the more likely conversion is from integer to float). Ada is designed to guarantee that what's done by the program is what's meant by the programmer, leaving as little room for compiler interpretation as possible.

So, in the above guide AdaCore define *strong typing* as the relative absence of *implicit* type conversions.

The other [answer](https://langdev.stackexchange.com/a/3742/1044) contains the following about *weak typing*:

> A weakly-typed language is one where the bits of a value can be reinterpreted as another type ...

The AdaCore [C to Ada Translation Patterns](https://learn.adacore.com/courses/Ada_For_The_Embedded_C_Developer/chapters/06_Translation.html) section of [Ada for the Embedded C Developer](https://learn.adacore.com/courses/Ada_For_The_Embedded_C_Developer/index.html) two ways in which Ada allows the *bits of a value* to be reinterpreted in the [Overlays vs. Unchecked Conversions](https://learn.adacore.com/courses/Ada_For_The_Embedded_C_Developer/chapters/06_Translation.html#overlays-vs-unchecked-conversions) section reinterpretations of bit values:

1. Overlays using an `Address` clause.
2. Unchecked Conversions, by instantiating a `Unchecked_Conversion` generic.

So, a language described has having *strong* typing may have language features or standard library functions which still allow reinterpretations of bit values.
> **Comments:**
> **username_14** (2024-04-28): I'm not sure how sound "implicit type conversion" is as a rule. If I can divide an `int` by a `float` because the languages let's `int / float` match `int / float`, is that implicit type conversion? If I can divide an `int` by a `float` because the language defines `int / float` to do the conversion explicitly but under the hood, is that implicit type conversion? A lot of languages allow `int / float` without technically using implicit conversions.  
> **username_0** (2024-04-28): @MisterMiyagi I don't know any language which defines `int / float` in any other way than "coerce the int to a float, then divide". In Java this is called a "[widening primitive conversion](https://docs.oracle.com/javase/specs/jls/se18/html/jls-5.html#jls-5.1.2)", for example. It would be difficult to define it any other way, since IEEE 754 doesn't specify any binary operations on floating point numbers where the other operand is not a floating point number.  
> **username_15** (2024-04-28): @kaya3 IEEE 754? Thousands of languages were created before it was first defined in 1985, so a huge number of languages aren't going to define it based on what IEEE 754 says.  
> **username_14** (2024-04-28): @kaya3 I'm not sceptical about the `int` value being converted to a `float` value, but about that being done necessarily as an implicit type conversion (via coercion as in your example). Any language that allows for explicit type conversions and operators can trivially define this via those mechanisms, without the type system doing anything implicitly.  
> **username_0** (2024-04-28): @MisterMiyagi In what sense is the conversion in `int / float` not implicit, if it is not written explicitly like `((float) x) / y`? It doesn't matter how that is implemented, whether by operator overloading or otherwise.  
> **username_0** (2024-04-28): @prosfilaes Unless any of those languages define `int / float` in a way which doesn't coerce the int to a float, that is irrelevant to my point.  
> **username_14** (2024-04-28): @kaya3 "It doesn't matter how that is implemented, whether by operator overloading or otherwise." It seems pretty pointless to classify the type system of a language by the rules implemented by a program. There's a good chance that someone, somewhere, out there overloaded some operator to accept mismatching types.  
> **username_0** (2024-04-28): @MisterMiyagi We are talking about the behaviours of built-in operators on built-in types. If the implementation details of that matter, then "language X has implicit conversions" is a meaningless statement because one implementation might satisfy your definition of "implicit conversions" and another might not, despite both implementations behaving identically. It is much more sensible to say that an implicit conversion is a type conversion which is not explicit in the code where the conversion occurs. In `int / float` there is a conversion from int to float without any syntax indicating it.  
> **username_0** (2024-04-28): To allay your concern about "classifying type systems", implicit conversions are a feature of the language's semantics as a whole, not of the type system alone. The fact that an `if` statement in Python coerces the condition's value to a `bool` is a fact about Python's `if` statements, not a fact about Python's type system.  
> **username_0** (2024-04-28): To me it would be extremely perverse to say that both `x / y` and `((float) x) / y` explicitly convert `x` to a float, when one has an explicit cast and the other does not; and it would be just as perverse to say that `x / y` does not convert `x` to a float but `((float) x) / y` does, when these terms have exactly the same operational semantics. So it is inescapable both that `x / y` performs a conversion, and that the conversion is not explicit. The word for "not explicit" is "implicit".  
> **username_12** (2024-04-30): @kaya3 My objection is that "convert" and "coerce" do not mean the same thing. If I write `float(x) / y` in Python (assuming a 3.x version in the CPython implementation) then an entire new object is created (a conversion) to represent the floating-point value numerically equal (within the limits of the precision of floats) to `x`. With `x / y`, the underlying value of `x` is coerced to a floating-point bit representation, within the underlying C runtime, only because the hardware demands it. There is nothing *inherent to* the concept of division that requires the operand types to match.  
> **username_12** (2024-04-30): And yes, I'm aware early versions of Python had a `coerce` builtin and `__coerce__` dunder. Aside from being a design mistake, the name was also simply wrong. Conversion creates a separate object, even if short-lived, that is expected to follow the language's object semantics. Coercion is an in-place reinterpretation, whether permanent or only for the duration of the operation.  
> **username_0** (2024-04-30): @KarlKnechtel [A coercion is an implicit conversion](https://en.wikipedia.org/wiki/Type_conversion#Implicit_type_conversion). I don't see how it matters whether the converted value exists in memory while the operation is applied; that is an implementation detail, you could perfectly well implement Python according to the spec without creating a new `float` object at runtime. It would still be the same language with the same semantics. What matters is that an expression of type `int / float` is operationally defined (in Python and C) as converting the int to a float and then dividing as floats.  
> **username_12** (2024-04-30): "It would still be the same language with the same semantics." The point is that, among other things, when you call `float(x)`, `float` has to be looked up (the name could have been rebound). You *have to* create a new `float` because the `float(x)` subexpression is separately meaningful. The Python developers are quite insistent on this. You get different bytecode and you are expected to be able to see the difference with the built-in debugger. It is very much considered part of the language's semantics.  
> **username_0** (2024-04-30): @KarlKnechtel I don't see how that is relevant to any point being made here. In an expression `x / y` where an int is divided by a float, there is no explicit conversion and hence no need to look up the name `float` to find the function, since that function is not called in this expression. Particularly, even if you rebind the name `float` in Python, `x / y` will still convert the integer to a float before dividing as floats. There is also no need to look up `float` by name when doing explicit conversions in C or Java, which also do this coercion for dividing ints by floats.  
> **username_0** (2024-04-30): You say that this conversion occurs in C "only because the hardware demands it", but it is also part of the C specification (likewise Java) that the result of the division is what you would get by converting the int to a float and then dividing as floats. Whether a conversion is carried out by the hardware is an implementation detail, but nonetheless an implicit conversion is part of the specified semantics of the language. As mentioned above, Java calls it a "widening primitive conversion", so to insist that it is not a conversion seems silly.  
> **username_0** (2024-04-30): You say *"There is nothing inherent to the concept of division that requires the operand types to match"*, but we are not talking about the concept of division, we are talking about the `/` operator in a programming language which has a specification, and that specification says there is a type conversion.  
> **username_0** (2024-04-30): You also say *"With `x / y`, the underlying value of x is coerced to a floating-point bit representation, within the underlying C runtime"*, but [that is not actually true in CPython](https://github.com/python/cpython/blob/4a5ad8469af9a6fc0ec1355eb203cc22bb4321d5/Objects/floatobject.c#L618); it still creates a new `float` object at runtime (the `CONVERT_TO_DOUBLE` macro does this by reference). Not that this matters, because my point is about the language's semantics, not the implementation.  
> **username_0** (2024-04-30): [Quoting the Python spec](https://docs.python.org/3.12/reference/expressions.html#binary-arithmetic-operations), *"The numeric arguments are first converted to a common type."*.  
---
### Answer by username_11 on 2024-04-29. Score: 1
For me, strong and weak typing imply that the compiler, runtime, or anything else (other than the code you write) is enforcing something about the types of various pieces of data. Variables, arguments, return values, etc (which I will refer to as "variables" henceforth).
The "something" part is indeed arbitrary, but when we constrain the domain to data types, to my mind it really only leaves one thing that could be enforced. Dynamic typing, duck typing, type inference, type coercion, and other features of a type system are not important, because they are not about enforcement.
A strongly typed language enforces that when a variable is declared, it is assigned a type (explicitly or implicitly), and for the duration of the variable's lifecycle, it will continue to have that type and only that type. A weakly typed language doesn't do this.
Let's pick on JavaScript as an example of a weakly typed language. The following is entirely reasonable:
var a = 123; // a has type number
a = "123"; // now a has type string.

And then let's contrast with JavaScript's strongly typed (IMO) cousin, TypeScript, in which the same code is not permitted.
var a = 123; // a has type number
a = "123"; // doesn't compile

JavaScript's type-related weakness goes beyond this enforcement with type coercion, but that's entirely separate from being weakly typed (i.e., you could have a language with one but not the other). That said, type coercion and weak typing go hand-in-hand in several ways, not least of which is the fact that they both allow subtle bugs to sneak into code way too easily for my personal taste. 
There are plenty more examples of weakly typed languages (Shell comes to mind). There's nothing wrong with them, but personally, I try not to use them in complex and/or production systems if I have a choice.
EDIT: apologies; I missed that the question is looking for authoritative answers. I looked to see if I can find any authoritative sources that share my opinion. What I found was just a single other use of "strong" and "weak" in a programming context which feels consistent:

A weak reference, in languages/runtimes with automatic memory management, is one in whose existence does not protect the value from being freed or garbage collected. You could rephrase my claim as "in a strongly typed language, the compiler or runtime protects the variable from being assigned a type-incompatible value." Therefore: "strong" implies some kind of protection, and "weak" implies a lack of said protection.
Nope, #1 is all I've got. leaves quietly
> **Comments:**
> **username_0** (2024-04-29): Welcome! Note that this question is asking for "authoritative" definitions ─ do you have a reference to show that this definition is used by researchers, language designers, etc.?  
> **username_11** (2024-04-29): Ah, sorry, I missed that part of the question. I don't, but I'll look around and see if I can find anyone authoritative who agrees with me.   
> **username_11** (2024-04-29): I've edited with a very weak hint of authoritative support for my opinion.   
> **username_12** (2024-04-30): "A strongly typed language enforces that when a variable is declared, variable is assigned a type (explicitly or implicitly), and for the duration of the variable's lifecycle, it will continue to have that type and only that type. A weakly typed language doesn't do this." JavaScript enforces this property on *values*. If you have two variables that name the same array, then you can make one or the other name an integer instead, but you can't make them *simultaneously* name an integer by *transforming* the array into an integer.  
> **username_11** (2024-04-30): @KarlKnechtel I don't follow. What does it mean for two variables to "name the same array"?  
> **username_12** (2024-04-30): Exactly what it sounds like. JavaScript's variables are names - just like Python's, almost all of Java's, and certain of C#'s. They have *reference semantics*, meaning that assigning to them *does not* copy the thing that was assigned, but instead makes that variable function as another name for the thing (mechanically: an automatically-deferenced pointer - *not* like a C++ reference type, because assignment "reseats" the reference rather than passing through to an assignment operator on the type.)  
> **username_11** (2024-04-30): okay, so you're saying `var a = [1,2,3]; var b = a;`, i.e. two references to the same item in memory? If so, then I think I get the point you're making, but I'm not sure how it's relevant. It feels some sort of zen thing, e.g. "Rain makes the ground wet." "Ah yes, but does it make the lake wet?" It's an interesting thing to think about, but it feels far outside the scope of the conversation.  
> **username_16** (2024-06-10): Your example is more indicative of the difference between static and dynamic typing. Weak typing would mean you could add `123 + "456"` and (depending on the rules governing type conversions) get either `579` or `"123456"` as an answer, rather than a type error.  
---
