Have you ever looked at a compiled js file? Things like spreading objects I to each other
{...a,...b}
End up being a nest object assign which is actually slower than spreading.
Have you ever looked at a compiled js file? Things like spreading objects I to each other
{...a,...b}
End up being a nest object assign which is actually slower than spreading.
And as mentioned by another user, you can choose your compile target to a specific version of JS which does support object spreading.
Whereas on Typescript the compilation process erases all this information, making it impossible to evaluate many such expressions.
There are multiple 3rd party solutions to this, such as: https://github.com/pelotom/runtypes
How does that work? I know next to nothing about the GHC, but in Haskell I would assume some tag is associated with each constructor (probably an integer) for the ADT and that the actual pattern matching gets compiled down to simple comparisons to either that integer or the right function for the more complex cases (pattern matching strings and other values).
TypeScript essentially does that, except that the tags are not going to be optimized by the compiler (they will remain strings if the dev uses them), and the "pattern matching" is just regular conditional checks (if, ternary or switch) with even the exhaustiveness check being done as a manual hack introduced by the dev and checked at compile-time (the else or default case assigning the value to the never type).
As for runtime values, Haskell also needs to validate types when deserializing, although that will be done by the deserialization libraries such as Aeson instead of deserializing and then optionally validating like in TS.
> TypeScript essentially does that, except that the tags are not going to be optimized by the compiler
What do you mean by this? Typescript erases type information during compilation. So you would not be able to emulate pattern matching against types on TS. Or you could if you manually added some common tag to every single data type like interface.
Or are you talking about just compile-time type checking on TS?
This is how you emulate them, I took it for granted and neglected to explicitly mention this is a moderately popular convention in TypeScript (those are the tags I referred to). fp-ts for example uses it all over the place.
With this the end result is essentially the same with compile-time type-safety for everything, and compiled down to an untyped binary or an untyped JS blob.
These strings should all be === at least if they are compiled together (the JITter could even intern them to make sure), I believe -- so it will typically be a single 64-bit ptr compare whether it's a string or int. Only in the case where you're constructing the DU tag at runtime for some reason would you need to compare the strings.
And C, Rust, Haskell, etc., all compile down to native code where you lose all type checking, so what? Outside of compiler bugs, what is statically proven at compile time doesn't change at runtime. (Yes, C also has a notoriously loose and abusable compile time type system, but that's a different issue.)
> Things like spreading objects I to each other
> {...a,...b}
> End up being a nest object assign which is actually slower than spreading.
Yes, if you use the default target (ES3), typescript emits JS compatible with downright ancient browsers which is super portable at the cost of being less efficient than targeting modern JS features, like spread syntax which was introduced in ES6.
You can also set the target to newer ECMAScript levels, including “ESNext”, at the cost of compatibility.
Yes and C still compiles to assembly with no type checking. What's your point?
Feel free to insert Rust or Haskell or whatever your language of choice is in place of C and my point remains the same. Sure you can include type information inside the assembly output and some sort of runtime code to handle that, but that doesn't change the fact that your compile target has no type system. Typescript could do the same if they desired, and in fact I think they offer the option.
Compiling a language with a type system to a language without is not a knock against that language's type system. Compiling typescript's decently comprehensive/expressive compile-time type system to javascript's basic runtime type system actually seems like a step up compared to a lot of other compilation targets.
> Typescript could do the same if they desired, and in fact I think they offer the option.
They very explicitly do not and have stated severally that it is not within the goals of the project to do so, which is something anyone actually familiar with the language should know.
> Compiling a language with a type system to a language without is not a knock against that language's type system
When you don't cherry-pick statements out of context, the point of what I said becomes rather obvious; if a language doesn't actually guarantee type safety at compile time, having a primary compilation target that takes a fascinatingly lax approach to data types is objectively worse (wrt type safety) than having one that's more strict.
Yes, obviously. Almost as though the fact that all languages end up as x86 or ARM opcodes at the end of the day has literally nothing to do with the merits and demerits of their respective type systems, but people keep bringing it up like some kind of gotcha when type systems get criticized.
Do you think that's an opinion I have expressed here?
While true, what's the point of this argument? You cannot get language-level runtime typechecking in the browser. At all. With any toolchain.
Runtime type checks is the lost link between static checks at compile time and arbitrary i/o data type in compiled js code.
You define a type in a similar way you would define TS types. At compile time it would give you the typescript type checks. At runtime it will help you determine if data has the correct type exactly as your typescript app expected.
There is extra work though, handling error if there is a faulty data type
Also iirc you can set the compile target to esnext and it will compile to the object spread expression.
Haskell compiles down to machine code, so...
I disagree. The point to which I refer was stating that because language A with type safety of some degree compiled to another form B without it obviates A's type safety altogether.
The destination isn't the point; it's the compilation of the beginning.