Hacker Newsnew | past | comments | ask | show | jobs | submit | more BiteCode_dev's commentslogin

Same feeling.

Between the cameras, the guards everywhere, the anti-thief systems on products, the alarm portals and the ticket check, the whole experience is super aggressive.


You can even add the inline importer in base64 that is pretty neat.

But I eventually printed that output, and put it in a dir I point my PYTHONPATH to so that I will always have it available.

Let's see if it sticks.


Moving the goal post of dumb search.


Eventually, node might allow JS to introspect those types.

That would be a huge win. Right now in Python, great tools like pydantic exist because Python can introspect said types, and generate checks out of them.

This mean you can define simple types, and get:

- type checking - run time data check - api generation - api document generation

Out of a single, standard notation.

Right now in JS, things like zod have to do:

    const mySchema = z.string();
Which is basically reinventing what typescript is already doing.


That's not entirely true. `z.string()` in Zod offers more than just type safety akin to TypeScript. TypeScript provides compile-time type checking, while Zod adds runtime validation and parsing.

For those unfamiliar:

`z.string()` effectively converts `mySchema` into a functional schema capable of parsing and validation.

For example:

`mySchema.parse("some data")` returns successfully.

`mySchema.parse(321)` throws an exception.

I've used it in places where you need runtime validation and in process verification - it works pretty well for that and you can extract the types from it via :

const A = z.string(); type A = z.infer<typeof A>; // string

Meaning if you define your types in zod first, and infer their types from that you get compile and runtime type checking.

---

It a bit of an overkill for nimble and fast code bases though - but works wonders for situations where in process proofing needs to be done, and in all honesty it isn't that big of a task to do this.


> Zod offers more than just type safety akin to TypeScript. TypeScript provides compile-time type checking, while Zod adds runtime validation and parsing.

Well of course it offers more, or you wouldn't be installing a library.

The problem is that even when you're expressing normal Typescript types, you have to use entirely different syntax. It's good that you can usually avoid double-definition, but it's still a big barrier that shouldn't be necessary.


There's also typescript-to-zod that makes it possible to generate the zod schemas from your types.


A lot of the focus by the TypeScript team is focused on alignment with the JavaScript language these days and novel new features such as run time types have all but been dismissed or at the very least pushed behind the TC39 JavaScript types proposal. Much like using decorators on variables outside of class structures was.

Having said that, TypeScript allows plugins, these are very rarely used as they augment the language by introducing other features that are transformed into the resulting JavaScript files. One plugin that relates to your suggestion of run time types is called Typia, it permits you to use your TypeScript type signatures at runtime with guards like `assert<MyType>(myValue)` where it intercepts the function call to construct an exhaustive if statement in the transpiled JavaScript checking the nature of the passed variable.

So while I don't see it being a part of the language in the next four to six years, there are at least libraries out there already that allow you to do it today.


If JS ever adds type checking, I hope it doesn't choose Typescript.

We need a type system that is actually sound and TS is intentionally unsound. We need a type system that doesn't allow bad coding practices like TS does. We need a type system that enforces program design that allows programs to be fast. We need a Hindley Milner type system.

If you want a module to be typed, add a `"use type"`. This should disallow bad parts of the language like type coercion. It should disallow things that hurt performance like changing object shape/value type or making arrays of random collections of stuff. Incoming data from untyped modules would either coerce or throw errors if coercion can't be done at which point the compiler can deeply-optimize the typed code because it would have far stronger type guarantees and wouldn't have a risk of bailing out.


having written ocaml in production for a few years, i think soundness comes at a cost of dev ergonomics. at least with the type systems of today’s industry languages.

it blows my mind weekly how ergonomic and flexible typescript’s type system is. it allows me to write great apis for my team mates.

is it possible for the type checker to end up in an infinite loop or for a junior developer to abuse “as”? absolutely, but it doesn’t really matter in practice.

i wouldn’t want to run typescript in rockets or submarines tho!


Ocaml types are USED by the compiler to generate FAST code.

TS types are IGNORED by the JIT to generate SLOW code.

All the features that make Typescript more ergonomic for devs also allow it to generate slower JS code. AssemblyScript tries to be TS for WASM and it doesn't support huge swaths of TS because they output unusably slow garbage.

I also suspect that more than a few Ocaml ergonomic issues are due to nominal typing. StandardML's structural typing and inference give an experience very similar to TS, but without the major soundness issues (though it must be noted that ANY generics in JS will be slow unless the compiler is creating multiple function variants).


for my use case (web dev) ts is fast enough. but i do miss the ocaml compile times!

it's mainly the lack of ad-hoc polymorphism that makes ocaml feel a bit clunky to me at times. but structural typing sure would be nice.

i used to avoid typescript because of similar soundness issues. but in the context of web dev this weird type system that evolved from adding types to javascript turned out to be so nice to use. it's bonkers because on paper it shouldn't be this nice haha.


Ocaml messed up with their operators. StandardML had a better approach and I hope a future version adds module typeclasses (to help limit the type soup we see in Haskell).

As I wrote elsewhere in this thread, TS makes it incredibly easy to unintentionally make megamorphic functions that don’t have any inline cache and don’t get optimized at all. You think you’re writing efficient, DRY code, but it’s really just dog slow because you’ve neutered the JIT.


> Ocaml messed up with their operators. ... I hope a future version adds module typeclasses

Do you mean modular implicits?[1] The original paper was published in 2014. There's an internship report from 2023 that summarizes the design and implementation issues:

https://modular-implicits.github.io/report.pdf

[1] https://arxiv.org/abs/1512.01895


https://www.cs.cmu.edu/%7Erwh/papers/mtc/short.pdf

I believe modular implicits and modular typeclasses are similar and aim to solve the same issues, but they are not quite the same.


What bad coding practices does TS allow, and why are they bad?


TS allows you to pass a read-only object to a method taking a read-write value:

    type A = { value: number; }
    function test(a: A) { a.value = 3; }
    function main() {
      const a: Readonly<A> = { value: 1 };
      // a.value = 2; <= this errors out
      test(a); // this doesn't error out
      console.log(a); // shows 3
    }


It seems super weird that this type checks, and it appears to be some sort of corner case explicitly implemented.

Normally typescript does not just allow implicit removal of a container type.

Like, you can't pass Array<A> to a function that just takes A.


Nice find. Never ran into this because I haven't mutated inputs in over 15 years.


If there's a bad way to write JS, TS has something available to make sure it's typed.

Does TS help you keep your functions monomorphic so they'll get optimized by the JIT? nope

Does TS keep your object shape from changing so it will get optimized by the JIT? it actively does the opposite giving TONS of tools that allow you to add, remove, modify, and otherwise mess up your objects and guarantee your code will never optimize beyond the basic bytecode (making it one or two orders of magnitude more slow than it could otherwise be).

TS doesn't do anything to prevent or even discourage these kinds of bad decisions. They "type soup" many projects fall into is another symptom of this. The big reason the types become such a mess is because the underlying design is a mess. Instead of telling programmers "fix your mess", TS just releases even more features so you can type the terrible code without fixing it.


> Does TS keep your object shape from changing so it will get optimized by the JIT? it actively does the opposite giving TONS of tools that allow you to add, remove, modify, and otherwise mess up your objects and guarantee your code will never optimize beyond the basic bytecode (making it one or two orders of magnitude more slow than it could otherwise be).

Can you elaborate or point to some of the tools? So I know what tools I may need to avoid


JS JITs use something called an inline cache (IC) to speed up the lookup of object shapes. JS JITs consider it to be a different shape if the keys are different (even if just one is added or removed), if the values of the same key are different types, and if the order of the keys change.

If you have a monomorphic function (1 type), the IC is very fast. If you have a polymorphic function (2-4 types), the IC function gets quite a bit slower. They call 5+ types megamorphic and it basically foregoes IC altogether and also disables most optimizations.

TS knows how many variants exist for a specific function and even knows how many of those variants are used. It should warn you when your functions are megamorphic, but that would instantly kill 90% of their type features because those features are actively BAD in JS.

Let's illustrate this.

    interface Foo {
      bar: string | string[]
      baz?: number
      blah?: boolean
    }
Looks reasonably typical, but when we use it:

    function useFoo(foo: Foo) { .... }

    useFoo({bar: "abc", baz: 123, blah: true}) //monomorphic
    useFoo({bar: "abc", baz: 123})             //now a slower polymorphic
    useFoo({bar: "abc"}) 
    useFoo({bar: ["b"], baz: 123}) 
    useFoo({bar: ["b"], baz: 123, blah: true}) //we just fell off the performance cliff
As you can see, getting bad performance is shockingly easy and if these calls were across five different files, they look similar enough that you'd have a hard time realizing things were slow.

Union/intersection aren't directly evil. Unions of a single type (eg, a union of strings) is actually great as it offers more specificity while not increasing function complexity. Even if they are a union of different primitive types, that is sometimes necessary and the cost you are paying is visible (though most JS devs are oblivious to the cost).

Optionals are somewhat more evil because they somewhat hide the price you are paying.

[key:string] is potentially evil. If you are using it as a kind of `any`, then it is probably evil, but if you are using it to indicate a map of strings to a type, then it's perfectly fine.

keyof is great for narrowing the possible until you start passing those keys around the type system.

Template unions are also great for pumping out a giant string enum (though there is a definite people issue of making sure you're only allowing what you want to allow), but if they get passed around the type system for use, they are probably evil.

Interface merging is evil. It allows your interface to spread across multiple places making it hard to follow and even harder to decide if it will make your code slow.

Overloads are evil. They pretend you have two different functions, but then just union everything together.

Conditional types are evil. They only exist for creating even more complex types and those types are basically guaranteed to be both impossible to fully understand and allow very slow code.

Mapped types are evil. As with conditional types, they exist to make complex an incomprehensible types that allow slow code.

Generics are the mother of all that is evil in TS. When you use a generic, you are allowing basically anything to be inserted which means your type is instantly megamorphic. If a piece of code uses generics, you should simply assume it is as slow as possible.

As an aside, overloads were a missed opportunity. In theory, TS could speed everything up by dynamically generating all those different function variants at compile time. In practice, the widespread use of generic everything means your 5mb of code would instantly bloat into 5gb of code. Overloads would be a great syntax to specify that you care enough about the performance of that specific function that you want to make multiple versions and link to the right one at compile time. Libraries like React that make most of their user-facing functions megamorphic could probably see a decent performance boost from this in projects that used TS (they already try to do this manually by using the megamorphic function to dispatch to a bunch of monomorphic functions).


Rescript?


Absolutely. People are sleeping on it.

If only projects like Bun/Deno/Node added runtime support for ReScript instead of TypeScript, collectively as the web-tooling industry, we'd be in a better place. But you can't win against the MS's marketing budget.

Also in hindsight, ReScript diverged away from OCaml, but the ReScript development team could have gone further by creating a runtime for ReScript. Then again I don't blame them - they are polishing the dev experience of ReScript and React.

This is the decade of writing shiny new runtimes - I hope somebody writes a ReScript runtime. Imageine ReScript, Core, rescript-webapi, typechecker, re-analyze, plus a bundler minifier etc baked into the runtime like Bun. Sounds like an interesting value proposition. Fingers crossed.


Does this mean Node can know if an exception is subclass of ValueError or an object is instance of SomeClass? I'm a TS newb, I thought types outside of array, object, number, string arent present in JS and Zod and typeguard functions return plain objects with "trust me bro".


In JS, classes do retain runtime information. So the `instanceof` is a real runtime operator that works by checking the prototype chain of an object. So checking subclasses can be done at runtime.

However, in TS other type information is erased at compile time. So if you write

    type Foo = "a" | "b";
the runtime code will see that just as a plain string.


You are right, they aren't. In the JavaScript languages which is what gets actually executed, there are no typescript types.

The parent commenter was talking about a way for nodejs to provide, via an API, the content of type annotations on fields/functions/variables like in python.

However, in python the type annotations are a property of the object at run time, whereas they are completely stripped before execution for typescript.

So I'm not sure how it would work except by changing the typescript philosophy of "not changing runtime execution"


> (even if they will not admit it publicly)

Saying you don't care about your user safety is actually often more costly than pretending you care, and then having a breach.


Indeed. A type means assigning a rigid category to something.

There is not a single taxonomy that is universal, it ends up like the Celestial Emporium of Benevolent Knowledge that decides animals into:

    those belonging to the Emperor,

    those that are embalmed,

    those that are tame,

    pigs,

    sirens,

    imaginary animals,

    wild dogs,

    those included in this classification,

    those that are crazy-acting,

    those that are uncountable,

    those painted with the finest brush made of camel hair,

    miscellaneous,

    those which have just broken a vase, and

    those which, from a distance, look like flies.
Then you have a new use case.


"plenty" is relative.

You don't see many GAFAM products created in either, and that's because of the trade off OP talks about.


I don't see many GAFAM products created in any functional language, even those with primitive type systems. Are you sure it is the type system that is scaring people away?


I don't like colored function for obvious reasons, but fully colorless for async means you don't know when things are async or not.

There are a lot of things I dislike in JS, but I think the I/O async model is just right from an ergonomics point of view. The event loop is implicit, any async function returns a promise, you can deal with promises from inside sync code without much trouble.

It's just the right balance.


> fully colorless for async means you don't know when things are async or not

The IDE can tell you.


> The IDE can tell you.

The only way the IDE can tell you is if the language tells it, or it guesses - and if it guesses then it will get it wrong sometimes. Which things are async or not is exactly the kind of thing that needs to be part of the language definition, so that all tools will agree about it and you won't have functions that are async in one IDE and not another, or async in a profiler but not an IDE, or...


Given Ruby culture of monkey patching, not always.

Besides, many people dev Ruby with a lightweight text editor, like text mate, that can't introspect code.


> ...culture of monkey patching...

I haven't seen more than a handful of PRs with monkey-patching in the last decade and even then they are accompanied by long-winded explanations/apologies and plans for removal ASAP (eg monkey-patching an up streamed fix that hasn't been released yet).

Also, ruby classes/methods can tell you all about themselves, so if you haven't got ruby-lsp up and running (and even if you do) you can always open a repl (on its own, in the server process, or in a test process) and ask the interpreter about your method. It's pretty great!

It's definitely the case that the editor's ability to understand code via static analysis is limited compared to other languages, but it's not like we ruby devs are navigating in the dark.


If you monkey patch, you get what you paid for - and an annotation at the call site or definition wouldn't help anyway!

If not, then we should be able to use the type annotations that are being added to also indicate async-ness.

If people decide to code Ruby "blind" (without a smart IDE), then that's their choice. There's no reason why someone using an IDE should have to pay for their decisions. We don't force people to manually and redundantly add names and types of parameters to call sites - it makes equally little sense to do the same for async. If someone decides to use a dumb IDE, then they can read the docs, exactly the same as they do for function parameters.


Can't the text editor open a shell where you can run the repl to do the inspection?


I’m all ears how IDE will determine that function is blocking 20 layers deep into third party library I don’t even have source code of.


Basically, you are ok with only the US influencing the rest of the world?

Because the US has control of the DNS root zones, is powerful enough to create a chip ban on China and has back doors in half the planet's machines through programs like PRISM or systems like IME. I think from an influence point of view, they are quite powerful enough.

Given the US also went to war with Irak despite the entire UN voting against it and while lying about WMD, have a mass spy program on their population, and will soon reelect a convicted felon, it's a good balance to have other parts of the world trying to have a say as well.

The human world is full of imperfections, but we usually average it at scale.


It's actually a golden age for fun video games, because we are swimming in new beautiful, engaging, original titles every year.

Some things really take you by surprise as well.

I never saw Inscryption, Disco Eliseum or Hades coming, and I think nobody did.

And even oldish games still have great value. I still play LoL or Isaac, and they are as good as they were on day 1.

Plus, you get the Switch then the Deck refreshed portable gaming experience. The latter made emulation so nice as well.

With terrific communities, insane speed runners, devs coming up with crazy new concepts and hardware that never stop to get better, it's hard to complain except that with a busy life, you will see only 1% of those masterpieces.


> I never saw (…) Hades coming, and I think nobody did.

I don’t think Hades came as a surprise to anyone who was already a fan of the devs from Bastion and Transistor.


Come on, Bastion is nice but nowhere as sophisticated as Hades. Neither the gameplay nor the replayability would have let you think the team had the ability at the time.

As for transistor, the story is basically "futuristic world is being destroyed by virus-type-invaders and your sword/companion is the key to beating it", with a predictable end and almost zero character dev.

Being able to make ok games doesn't translate to the skill to make a masterpiece.

It was a quantum leap.

It would be like saying you can deduce Divinity Original sin 2 would be amazing because you played the first one.


Inscryption is a must play.


I will remember it forever, it's a unique experience.

But it's such a weird combination of aesthetic, story telling and gameplay I have to assume it prevents a huge part of the gaming population from enjoying it.

If anybody read those comments, DO NOT LOOK THE GAME UP if you plan to play it. Go blind.


I binged it during the time I was trapped in my room with COVID. You're right, it is a very weird game(s?) in the best way, it's literally sent me off on a card game design jaunt that's still ongoing haha. And I found myself loving the characters of the, what was it, ocelot and the wizard apprentice who is glad to have any kind of STIM-U-LA-TION?


I disagree. Sure, there are fun games, but they're so hard to find among all the crap


The noise/signal ratio is worse for everything today: movies, music, tv shows.

But "finding good games requires a tiny bit of effort to me" is a first-world problem.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: