HN user

dcreager

856 karma

[ my public key: https://keybase.io/dcreager; my proof: https://keybase.io/dcreager/sigs/qAdDFd-q6TDjesY0__JJ6GnOrnO0mRcDVpvmhC1958M ]

Posts8
Comments109
View on HN

Does that not also suggest (cautious, make sure we back it up with our actions) optimism about this acquisition? We're not breaking up the band. These tools will be in the same hands as before. And it would be extremely value-destructive to bring in a team like ours and then undermine what made us valued and successful.

I've been in the industry for similarly long, and I understand and sympathize with this view. All I can say is that _right now_, we're committed to maintaining our open-source tools with the same level of effort, care, and attention to detail as before. That does not change with this acquisition. No one can guarantee how motives, incentives, and decisions might change years down the line. But that's why we bake optionality into it with the tools being permissively licensed. That makes the worst-case scenarios have the shape of "fork and move on", and not "software disappears forever".

I hope this means the Astral folks can keep doing what they are doing, because I absolutely love uv (ruff is pretty nice too).

That is definitely the plan!

My understand is Astral's focus for ty has been on making a good experience for common issues, whereas they plan for very high compliance but difficult or rare edge cases aren't are prioritized.

I would say that's true in terms of prioritization (there's a lot to do!), but not in terms of the final user experience that we are aiming for. We're not planning on punting on anything in the conformance suite, for instance.

Can you elaborate what you mean by decorative?

If you run a type checker like ty or pyright they're not decorative — you'll get clear diagnostics for that particular example [1], and any other type errors you might have. You can set up CI so that e.g. blocks PRs from being merged, just like any other test failure.

If you mean types not being checked at runtime, the consensus is that most users don't want to pay the cost of the checks every time the program is run. It's more cost-effective to do those checks at development/test/CI time using a type checker, as described above. But if you _do_ want that, you can opt in to that using something like beartype [2].

[1] https://play.ty.dev/905db656-e271-4a3a-b27d-18a4dd45f5da

[2] https://github.com/beartype/beartype/

There was a hang/performance bug [1, 2] that was reported just after the beta release, which we've since fixed [3]. You might try seeing if we get through your entire project now?

(And as an aside, there _is_ a verbose mode: if you add `-vv` you'll get DEBUG-level log messages printing out the name of each file as we start to check it, and you can set TY_MAX_PARALLELISM=1 in your env to make it very clear which file is causing the hang. That's how we debug these kinds of issues when they're reported to us.)

[1] https://github.com/astral-sh/ty/issues/1968

[2] https://github.com/astral-sh/ty/issues/1993

[3] https://github.com/astral-sh/ruff/pull/22030

Yes, we love TypeForm! We plan to support it as soon as the PEP for it lands. Under the covers, we already support much of what's needed, and use it for some of our special-cased functions like `ty_extensions.is_equivalent_to` [1,2]. TypeForm proper has been lower on the priority list mostly because we have a large enough backlog as it is, and that lets us wait to make sure there aren't any last-minute changes to the syntax.

[1] https://github.com/astral-sh/ruff/blob/0bd7a94c2732c232cc142...

[2] https://github.com/astral-sh/ruff/blob/0bd7a94c2732c232cc142...

Stepping away from Forth in particular, one of the benefits of a stack-based / concatenative language is that it's easy to implement on constrained hardware. uxn [1] is a great example of that.

And shameless self-promotion, if you're interested in how these kinds of languages compare with more traditional named-based languages, with more theoretical constructs like the lambda calculus and combinatory logic, and with gadgets like a PyBadge — well you're in luck! I gave a talk about exactly that at the final Strange Loop [2].

[1] https://100r.co/site/uxn.html

[2] https://dcreager.net/talks/concatenative-languages/

competing with PyPI

pyx doesn't compete with PyPI; it's a private registry that companies can use e.g. to host internal-only packages, or to provide curated views of things like PyPI for compliance reasons.

making changes which seemingly require their client (uv) be used

That's an explicit non-goal: "You won't need to use pyx to use uv, and you won't need to use uv to use pyx."

The Open Firmware bootloader also used a Forth as its command-line interface. That was used on PowerPC Macs before Apple switched over to Intel. (So, you know, two processor architectures ago.)

A common theme is that Forth-likes are very easy to implement on constrained hardware. I have a Strange Loop talk a couple of years ago where I go into this at the end, calling out uxn from the Hundred Rabbits folks. You might consider that more "hobbyist" than "production", but people are deriving real joy making apps and games in that ecosystem.

https://dcreager.net/talks/concatenative-languages/

https://100r.co/site/uxn.html

For a counterargument, this is the most commonly cited argument that I've seen _against_ using a Forth-like in an industrial context:

https://yosefk.com/blog/my-history-with-forth-stack-machines...

I think that's a genuine error, since as you say, `None` is a possible value for `b` according to your signature.

To handle this you would need to use "narrowing" to separately handle the case where `b` is `None`, and the case where it is not:

  def square(a: Union[int, float], b: Optional[int] = 2) -> float:
      if b is None:
          return 0
      else:
          c = a**b
          return c
https://play.ty.dev/97fe4a09-d988-4cc3-9937-8822e292f8d1

(This is not specific to ty, that narrowing check should work in most Python type checkers.)

Well ours is not yet implemented, so it's too early to say whether they're compatible. :-)

But less snarkily, we do talk to them often (and the authors of other tools like mypy and pyright) to make sure we aren't introducing gross incompatibilities between the different type checkers. When there are inconsistencies, we want to make sure they are mindful rather than accidental; for good reasons; spec-compliant; and well documented.

Gradual typing means that an implicit "any" (unknown type) anywhere in your code base is not an error or even a warning. Even in critical code you thought was fully typed. Where you mistakenly introduce a type bug and due to some syntax or inference limits the type checker unexpectedly loses the plot and tells you confidently "no problems in this file!"

This is a good point, and one that we are taking into account when developing ty.

The benefit of the gradual guarantee is that it makes the onboarding process less fraught when you want to start (gradually) adding types to an untyped codebase. No one wants a wall of false positive errors when you first start invoking your type checker.

The downside is exactly what you point out. For this, we want to leverage that ty is part of a suite of tools that we're developing. One goal in developing ty is to create the infrastructure that would let ruff support multi-file and type-aware linter rules. That's a bit hand-wavy atm, since we're still working out the details of how the two tools would work together.

So we do want to provide more opinionated feedback about your code — for instance, highlighting when implicit `Any`s show up in an otherwise fully type-annotated function. But we view that as being a linter rule, which will likely be handled by ruff.

[ty developer here]

We are happy with the attention that ty is starting to receive, but it's important to call out that both ty and pyrefly are still incomplete! (OP mentions this, but it's worth emphasizing again here.)

There are definitely examples cropping up that hit features that are not yet implemented. So when you encounter something where you think what we're doing is daft, please recognize that we might have just not gotten around to that yet. Python is a big language!

I am strongly against ty behaviour here.

[ty developer here]

Please note that ty is not complete!

In this particular example, we are tripped up because ty does not do anything clever to infer the type of a list literal. We just infer `list[Unknown]` as a placeholder, regardless of what elements are present. `Unknown` is a gradual type (just like `Any`), and so the `append` call succeeds because every type is assignable to `Unknown`.

We do have plans for inferring a more precise type of the list. It will be more complex than you might anticipate, since it will require "bidirectional" typing to take into account what you're doing with the list in the surrounding context. We have a tracking issue for that here: https://github.com/astral-sh/ty/issues/168

Note that we're not ever spinning up a Python interpreter to run your code, or monitoring an existing running Python process. So we do need some kind of metadata.

But yes, if you have a Python version specified in pyproject.toml, we respect that, and if you have a virtualenv, we can see the Python version that was used to create that. And that's what we use to type-check your code.

The default being discussed here is what we fall back on if that project metadata isn't available.

We are planning on shipping an LSP front end, and the goal is for that to include code completions. Though to set expectations, they will probably not be that sophisticated on day one. There's a lot of interesting work that we could do here, but it will take time!

The code is definitely open source from a licensing perspective, but we are also trying to ensure that a healthy community forms around our tools as well. We've been developing ty in the open for the last year or so, and it already includes significant work from external contributors. This is definitely not a project where only Astral-paid engineers can contribute.

Yes, if you have a Python version specifed in pyproject.toml, for instance, we respect that, and that's what we use to type-check your code. The default being discussed here is what we fall back on if that project metadata isn't available.

To add to the complexity, you have to worry about not just which language you're analyzing, but also which language the type-checker is implemented in.

So if we were to do this for ty, we would have to carefully design the internal data types and algorithms that we use to model Python code, so that they're extensible in a robust way.

But we would also have to decide what kind of Rust plugin architecture to use. (Embed a Lua interpreter? dlopen plugins at runtime? Sidecar process communication over stdin/stdout?)

Solvable problems, to be sure, but it adds to the amount of work that's needed to support this well — which in turn affects our decisions about whether/when to prioritize this relative to other features.