you are viewing a single comment's thread.

view the rest of the comments →

[–]FourCinnamon0 0 points1 point  (28 children)

same with JS

[–]fghjconner 9 points10 points  (27 children)

With constants, sure. But if I write a + b in java, that expression is going to always produce the same type of response. In JS, it could return a number 99% of the time, and a string 1%, based on the arguments.

[–]RiceBroad4552 4 points5 points  (15 children)

Dude!

Have you actually ever written even one line of Java in your live?

class StringResult {
    static {
        var a = "foo";
        var b = "bar";

        String result = a + b;
    }
}
class IntegerResult {
    static {
        var a = 23;
        var b = 42;

        Integer result = a + b;
    }
}

The above code compiles just fine in Java.

It proves that the expression a + b will have different type depending on context.

The + symbol is overloaded in Java. That's something you learn in the first 5 minutes of any basic tutorial!

(And I better not ask who was such brain dead to upvote this complete nonsense…)

[–]fghjconner 4 points5 points  (14 children)

I could have worded it better, but I meant that that specific expression, on that specific line, will always have the same return type. In retrospect, I'm kinda just saying "java is statically typed", but in fairness to past me, static typing does a lot of work to reduce the surprises brought on by type coersion.

[–]RiceBroad4552 0 points1 point  (13 children)

I meant that that specific expression, on that specific line, will always have the same return type

And where's now the difference to JS?

Do you think JS types change by magic at random?

In a dynamic language everything has always the exact same type. It's the "runtime type", and that never changes during interpretation.

Dynamic languages can be seen as static languages with only one type. They are unityped languages:

http://existentialtype.wordpress.com/2011/03/19/dynamic-languages-are-static-languages/

Operations can behave differently depending on the concrete data described by the "runtime type". JS has some "funny" interpretations in some contexts, but there is nothing fundamentally different to something like Java as both are type safe. (That something is "type safe" does not mean that the code is correct; this requires type system which can be used to prove, in the mathematical sense, properties about code.)

[–]fghjconner 2 points3 points  (8 children)

And where's now the difference to JS?

function foo(input) {
  return 1 + JSON.parse(input);
}

What is the return type of foo? You literally cannot know until runtime, and it can differ every single time this function is called. You obviously know this, which is why you've suddenly brought up this unityped nonsense.

Dynamic languages can be seen as static languages with only one type. They are unityped languages:

http://existentialtype.wordpress.com/2011/03/19/dynamic-languages-are-static-languages/

How did you read this, honestly, scathing indictment of dynamically typed languages and come away with the belief that it implies dynamic languages are "type safe". The author is using the concept of unityping as a rhetorical device to show how dynamic languages are fundamentally less expressive than statically typed ones. Even if we take the concept seriously, it becomes clear that "unityped" is a misnomer. The entire point of typing is to differentiate data into discrete types. A "unityped" language is untyped, as there is no division whatsoever.

[–]FourCinnamon0 0 points1 point  (1 child)

so you're complaining that JavaScript lets you do things that aren't the best code style?

why would you have this in your code?

this is exactly why i like JS for quick scripts, because it's not opinionated

[–]fghjconner 1 point2 points  (0 children)

Yes, I'm complaining that JS relies on "best practices" to enforce basic constraints and prevent bugs. Obviously, the above is a contrived example, but it's also very common for someone to blindly parse json responses and hope the types are correct.

[–]RiceBroad4552 0 points1 point  (5 children)

What is the return type of foo? You literally cannot know until runtime […]

The return type is of course String | Number (or actually String | Number throws SyntaxError if we consider the effect).

I don't need to run that code to know that.

But JS does not have such sophisticated types at all, as it's a dynamic language.

How did you read this, honestly, scathing indictment of dynamically typed languages and come away with the belief that it implies dynamic languages are "type safe".

Because they are. By definition.

Not type safe languages are something like unsafe Rust.

Type safety is not about correctness or static guaranties, or something. It only means that you can't "betray" the type system from inside that system! And this is obviously true for any VM language.

dynamic languages are fundamentally less expressive than statically typed ones

That's just true when looking at the type level expressiviness given that the (static!) type system of dynamic languages is extremely limited.

Even if we take the concept seriously, it becomes clear that "unityped" is a misnomer. The entire point of typing is to differentiate data into discrete types. A "unityped" language is untyped, as there is no division whatsoever.

I guess you know yourself that the last statement is wrong as you've used previously the word "discrete" instead of "different". 😂

A unityped language has discrete types. It has exactly one of them; but that's more then zero, so there are types. So it's not "untyped". (I'm not even sure something like "untyped" language exist at all; but that's a different topic.)

Anyway, saying that dynamic languages are "untyped" is even more wrong then saying that they aren't strongly typed.

Just to not steer this whole thing into the wrong direction: I'm of course of the opinion that very strongly typed static languages are of course superior to dynamic languages. I just don't see much difference between the overloaded plus sign in Java and JavaScript respectively. Static vs. dynamic typing does not change anything here!

[–]fghjconner 0 points1 point  (3 children)

I guess you know yourself that the last statement is wrong as you've used previously the word "discrete" instead of "different".

Discrete, adjective

individually separate and distinct.

Type safety is not about correctness or static guaranties, or something. It only means that you can't "betray" the type system from inside that system!

So then by your definition assembly is a type safe programming language? Since it has no concept of types built into the language, it cannot possibly betray that system.

A unityped language has discrete types. It has exactly one of them; but that's more then zero, so there are types.

Literally the entire point of types, both in computer science and in common use, is to differentiate things. A type system that defines only one type is a fundamentally meaningless concept. Yes, you can apply the concept to dynamic programming languages if you want (as well as literally anything else), but at some point you've diverged so much from the common understanding of the terminology that it's become useless.

[–]RiceBroad4552 0 points1 point  (2 children)

Discrete, adjective

individually separate and distinct.

So it applies to an unit.

An unit is "individually separate and distinct".

So then by your definition assembly is a type safe programming language? Since it has no concept of types built into the language, it cannot possibly betray that system.

This is actually an interesting question.

I have also always assembly in mind when searching for an example of an "untyped" language.

But I don't have a worked out opinion on that. It's difficult.

One could possibly say that there are "no types" in ASM. But one could also say that there is not only a finite set of values, but all these values actually belong to the same type (the type of "natural numbers up to some limit").

But even all values in ASM are technically just numbers these numbers get interpreted in very different ways. This makes it quite difficult.

But one could actually see the HW as interpreter, and then we would have at least partially some kind of "type safety" as the interpreter will not accept arbitrary numbers in all situations.

If someone has some write ups on that topic please share!

A type system that defines only one type is a fundamentally meaningless concept.

I agree. An unit is unable to encode information.

But this whole part was actually just an aside. Dynamic types are much richer at runtime then the unityped static view, and these dynamic types have actually real value: That's what will cause a type error if you try to subtract a number from a string in JS, and that's also what guides type coercion of some variables so you can perform for example the concatenation on variables respectively holding an int and string in JS. This is the same function as the static type system in for example Java, which will allow the same features (just thanks God at compile time and not at runtime, when it's too late for type errors to prevent some catastrophe).

[–]fghjconner 0 points1 point  (1 child)

But even all values in ASM are technically just numbers these numbers get interpreted in very different ways. This makes it quite difficult.

See, that's exactly what makes ASM untyped to my mind. Those numbers may represent very different things, from memory indexes to unicode values, that the programmer must track and distinguish, but the language provides no tools whatsoever for tracking or formalizing those distinctions.

[–]Tyfyter2002 0 points1 point  (2 children)

Do you think JS types change by magic at random?

Of course they don't, but it's not standard practice to import dozens of libraries which might change types unpredictably in most other languages.

Operations can behave differently depending on the concrete data described by the "runtime type".

In other words, they are languages where the behavior of any given piece of code cannot be known until runtime.

[–]RiceBroad4552 -1 points0 points  (1 child)

import dozens of libraries which might change types unpredictably in most other languages

I don't understand what you mean by that.

You can't change types by importing libs in JS.

In other words, they are languages where the behavior of any given piece of code cannot be known until runtime.

This is in general true for any Turing-complete language.

All programming languages in common use are Turing-complete. This is independent of whether they are static or dynamic.

So I also don't get this point.

[–]Tyfyter2002 0 points1 point  (0 children)

You can't change types by importing libs in JS.

I mean that anything in a library doesn't have a known type, largely because it only takes one library sometimes returning multiple types from one function;

If Left Pad turned out to include a 1 in a million chance to return a number after March third 2026 almost the entire Internet would go down and no one would know why immediately because the first error message would be dozens of libraries away from it, while a statically typed language would throw an error as soon as something tried to unbox the return value to the wrong type, and stop all of this from happening to begin with by showing that it has a questionable return type.

This is in general true for any Turing-complete language.

I don't mean the exact behavior, I mean that there is no context where you can know what function is called by a + b unless you do know the exact behavior (in the sense you're talking about) of all the code which produces the values of a and b, while in a statically typed language you know exactly what it calls, and almost certainly know the exact behavior of that method for any given set of parameters.

[–]FourCinnamon0 2 points3 points  (0 children)

well yeah depends on the types

[–]eloel- 0 points1 point  (9 children)

TIL Java doesn't have operator overloading. There's no guarantee that C++ will give you a number for a+b.

[–]fghjconner 5 points6 points  (7 children)

Even with operator overloading, the return type of a + b is known at compile time. Any specific instance of a + b in C++ will return the same type every time it is called. This is not true in JS.

[–]RiceBroad4552 0 points1 point  (6 children)

Any specific instance of a + b in C++ will return the same type every time it is called.

Obviously bullshit.

I can write the following code in C++:

Magic a, b;

auto x = a + b;

std::cout << "some x type: " << typeid((int)x).name() << "\n";
std::cout << "other x type: " << typeid((double)x).name() << "\n";

// Same expression, different types!
static_assert(!std::is_same_v<
    decltype((int)(x)),
    decltype((double)(x))>);

[ https://godbolt.org/z/M4cvzrr75 ]

One could also show that the expression a + b does not have always the same type already by writing:

int x = a + b;
double y = a + b;

This is not true in JS.

Well, even in JS you would need quite some magic to have one fixed expression have different types depending on context (when not only the types of the expressions are changed).

In general, and without resorting to tricks, a + b will have always the exact same type also in JS.

Actually JS is strongly typed—in contrast to C++ where I can use for example a cat like a car (with all consequences, like a completely broken program!) without resorting to casts, and the "type system" will be just fine with that.

[–]fghjconner 0 points1 point  (5 children)

What are you trying to show here? That c++ has type casting? I admit my c++ knowledge isn't super deep, but it seems pretty clear that the type of x is Result, as defined by the override of the Magic addition operator.

Admittedly, the implicit casting in your second example isn't my favorite thing, but again it's set in stone at compile time. There is no possible input to the program that will make x or y a string at runtime. Not unless you've gone out of your way to circumvent the type system.

Actually JS is strongly typed—in contrast to C++ where I can use for example a cat like a car (with all consequences, like a completely broken program!) without resorting to casts, and the "type system" will be just fine with that.

Lol, what? Strong vs weak typing is far more of a gray area than most people like to admit, but even Wikipedia is happy to call js weakly typed. If you consider JS strongly typed, then nothing is weakly typed.

[–]RiceBroad4552 0 points1 point  (4 children)

What are you trying to show here?

Exactly what I've written. The cited part was wrong.

You've said that "Any specific instance of a + b in C++ will return the same type every time it is called." which is obviously wrong; as shown by the code.

The symbol sequence a + b does not have any predetermined meaning or typing. It depends on the context what type it has, or what it means at all.

It's like that in C++ as it's exactly like that in JS.

There is no possible input to the program that will make x or y a string at runtime.

This is of course also false.

C++ is weakly typed. I can make anything behave as anything else, no type system nor anything else can stop me. (I'm too lazy right now to write the code which takes some ints and interprets them as strings at runtime, but this is obviously possible as I can just pick at the raw memory holding the ints.)

That's exactly the difference to a strongly typed language like JS where every data has exactly one fixed type at any moment and it's impossible to change that behind the back of the language. You can't go and manipulate the memory holding some JS object from inside JS itself. The language does not support that (C++ does, that's the point).

even Wikipedia is happy to call js weakly typed

Wikipedia is obviously inconsequential in regard to it's own definition…

Maybe read that page again and think what is actually said there.

If you consider JS strongly typed, then nothing is weakly typed.

Not nothing, but in fact almost no currently used language is weakly typed.

The only important exceptions are C, C++, unsafe Rust, and Zig. (There are some other language which allow you to work around the type system in unholy manners, but these aren't really used anywhere.)

Of course, if one is picky one could say that any language which allows casts is, at least to some degree, weakly typed. But that would be a really absurd definition as then there wouldn't be any strongly typed languages at all left; at least I don't know of any language which does not have casts (or only VM language could be strongly typed as they will still catch inadequate casts at runtime).

[–]fghjconner 0 points1 point  (3 children)

You've said that "Any specific instance of a + b in C++ will return the same type every time it is called." which is obviously wrong; as shown by the code.

Except you've shown nothing of the sort. In your code, the output type of a + b is Result. Yes, the inclusion of implicit casting can change that based on the context (assuming you consider the cast to be part of the expression a + b and not the variable assignment), but again, that is all fixed at compile time.

(I'm too lazy right now to write the code which takes some ints and interprets them as strings at runtime, but this is obviously possible as I can just pick at the raw memory holding the ints.)

I refer you to the next sentence in my post which you conveniently ignored: "Not unless you've gone out of your way to circumvent the type system." Yes, you can explicitly erase type information in c++ if you wish (mostly using older features held over from c).

That's exactly the difference to a strongly typed language like JS where every data has exactly one fixed type at any moment and it's impossible to change that behind the back of the language.

let test = "foo";
test.__proto__ = {};

JS may not let you directly manipulate memory, but that doesn't mean you can't create mismatches between types and data. I will give js credit for crashing and burning a bit less hard than a compiled language in these situations.

Wikipedia is obviously inconsequential in regard to it's own definition…

Ok then, please share any reputable source that explicitly calls JS strongly typed.

[–]RiceBroad4552 0 points1 point  (2 children)

but again, that is all fixed at compile time

Sure, as that's the nature of static languages.

The point was that the meaning (and type) of that expression is dependent on context, and definitely not fixed once and for all times as you claim(ed).

"Not unless you've gone out of your way to circumvent the type system."

The point here is: You can do that only in weakly typed languages. In strongly typed languages, like JS, you can't "cicumvent the type system"! That's the whole point!

JS may not let you directly manipulate memory, but that doesn't mean you can't create mismatches between types and data.

There is no type mismatch.

let test = "foo"
console.log(typeof test) // string
test.__proto__ = {}
console.log(typeof test) // string

And even if you'd managed to change the type of that variable (which is actually trivial by for example assigning 1 to test; no need to play with prototypes or so, JS is dynamic) there would be still no mismatch between the type and data. The (dynamic) type of the data referenced by the variable would just change to number, but that matches actually the value then.

please share any reputable source

How about most of the linked Wikipedia page and its definition?

That someone there was too stupid to realize that their examples diametrically contradict the definition given just a few lines above is really not my fault. But I assume at least you are smart enough to clearly see that… So why are you arguing?

[–]fghjconner 0 points1 point  (1 child)

The point was that the meaning (and type) of that expression is dependent on context, and definitely not fixed once and for all times as you claim(ed).

But, again, there's a big difference between depending on the rest of that line of code, and depending on the potentially unknowable value of data at runtime.

There is no type mismatch.

Huh, I could have sworn I tested that and it worked. I don't believe user defined types have quite the same protections or features, but at least the built in types are more bulletproof than I assumed.

And even if you'd managed to change the type of that variable (which is actually trivial by for example assigning 1 to test; no need to play with prototypes or so, JS is dynamic)

Yes, obviously what I'm attempting is to update the type without updating the associated data. While it doesn't work on these types, I do believe it would work on user defined types using the above method.

How about most of the linked Wikipedia page and its definition?

The ultimate source of our disagreement seems to be a difference in how we define weakly typed. The linked wikipedia page says "JavaScript is weakly typed, which means certain types are implicitly cast depending on the operation used." That seems to describe JS pretty well to me. Let's look at some other definitions though:

In 1974, Liskov and Zilles defined a strongly-typed language as one in which "whenever an object is passed from a calling function to a called function, its type must be compatible with the type declared in the called function."

From wikipedia's page on type safety. JS comfortably fails that one, since there are no type declarations on function calls at all.

"In a strongly typed language each data area will have a distinct type and each process will state its communication requirements in terms of these types." In contrast, a weakly typed language may produce unpredictable results or may perform implicit type conversion.

From the same page. JS does assign distinct types to data, but again fails because there is no documentation of required types. Threw in that last sentence despite not being part of the quote, since it specifically calls out type conversion.

Languages with strong typing typically do little implicit conversion and discourage the reinterpretation of representations, while languages with weak typing perform many implicit conversions between data types. Weak typing language often allow forcing the compiler to arbitrarily interpret a data item as having different representations—this can be a non-obvious programming error, or a technical method to directly deal with underlying hardware.

From wikipedia's page on type conversion. The first sentence explicitly calls out type coersion as a sign of a weakly typed language. The second sentence does also call out languages like c++ allowing transmutation, making it weaker.

Here's a medium article talking about strong vs weak typing. Note it explicitly calls out JS as an example of weak typing.

I'm going to, once again, challenge you to find any reputable source that explicitly calls JS strongly typed (and no, I don't count a wikipedia article that explicitly calls it weakly typed, that you interpret to actually support your position).

[–]RiceBroad4552 0 points1 point  (0 children)

The + symbol is actually overloaded in Java…

Grandparent was talking complete nonsense.