[HN Gopher] T-Ruby is Ruby with syntax for types
___________________________________________________________________
T-Ruby is Ruby with syntax for types
Author : thunderbong
Score : 165 points
Date : 2025-12-26 20:27 UTC (1 days ago)
(HTM) web link (type-ruby.github.io)
(TXT) w3m dump (type-ruby.github.io)
| wsc981 wrote:
| In the context of Lua, I've taken a liking to LuaLS (Lua Language
| Server). You can just write your Lua scripts with annotations
| (where needed) and the language server can help auto-complete and
| verify type usage. No compilation step needed.
|
| I never tried "typed Lua" variants (such as MoonScript IIRC), but
| I believe those do require a compilation step.
| kace91 wrote:
| Honest question:
|
| I like typescript and I think it makes sense:, the web makes you
| married to JavaScript, so it's the reasonable path forward if you
| want types in that context.
|
| But what is the point of the recent wave of types for python,
| Ruby, and similar languages?
|
| If it's type safety you want there, there's a bajillion other
| languages you can use right?
| wawj wrote:
| Languages take time to get used to and to get productive in. IF
| you already know Ruby, and want the same safety as C# for
| instance, then this makes sense.
| actionfromafar wrote:
| Crystal is a cool Ruby-like.
| shevy-java wrote:
| I agree on the first part. This is valid for all programming
| languages though.
|
| I disagree that you get the same safety as C# anywhere
| though. But even more importantly - I don't think people
| should write C#-like code in ruby. It does not really work
| that well. It is better to write ruby like ruby; and even in
| ruby there are many different styles. See zverok using
| functional programming a lot. I stick to oldschool boring
| OOP; my code is very boring. But usually well-documented. I
| want to have to think as little as possible because my brain
| is very inefficient and lazy; zverok has a good brain so he
| can write more complex code. It is very alien code to me
| though, but he also documents his code a lot. You can find
| his code or some of his code here, it is a quite interesting
| ruby style, but also alien to me:
| https://zverok.space/projects/
|
| (Ruby also adopted some habits from perl. I also don't think
| writing perl-like ruby makes a lot of sense. See also the old
| global variables inspired by perl; I can not recall most of
| them off-hand, so I avoid using them. My brain really needs
| structure - it is such a poor thinking machine really. And
| slow. My fingers are much faster than my brain really.)
| matteotom wrote:
| At least for Python (since I'm more familiar with Python code
| and the Python ecosystem): progressive typing lets you
| incrementally add typing to an existing Python codebase. So you
| can have at least some of the benefits of typing for new or
| updated code without needing to re-write in a new language.
| ReflectedImage wrote:
| Gradual typing is the worse of both worlds.
|
| You get the complexity and slower development times of using
| statically typed languages along with the bad performance of
| using dynamically typed languages.
| ck45 wrote:
| Is this based on your experience or is it just an
| assumption? I only have anecdotes, but it does not reflect
| your claims, rather the exact opposite. A lot of the
| boilerplate code doesn't need to be type annotated, but
| annotating the main business logic doesn't take more time
| and is not more complicated, but instead type annotations
| help write code that is more clear, more obvious, and it
| adds some kind of documentation.
| creshal wrote:
| It really depends on how you tackle gradual typing on a
| project level. The easiest way to sabotage is a "any new
| code must be fukly type checked" requirement, because it
| often means you also need to add type hints to any code
| you call, which leads to Optional[Union[Any]] nonsense if
| you let juniors (or coding assistants) go wild.
|
| As always, no fancy new tech is a substitute for
| competent project management.
| rurban wrote:
| Nonsense. You get the simplification and faster development
| times of knowing some variable types statically, plus the
| performance improvements for the compiler which can move
| the type checks from runtime to compile-time. Plus all the
| new optimization possibilities.
|
| Common Lisp showed you the way. But almost none looked at
| it. Only PHP did.
| dajonker wrote:
| At least CPython and CRuby (MRI), the most common
| implementations of each language, ignore all type hints
| and they are not able to use them for anything during
| compile or runtime. So the performance argument is
| complete nonsense for at least these two languages.
|
| Both Python and Ruby (the languages themselves) only
| specify the type hint _syntax_ , but neither specifies
| anything about _checking_ the actual types. That exercise
| is left for the implementations of third party type
| checkers.
| rurban wrote:
| Because the anti-types crew showed up and sabotaged it.
| Similar with perl and lua.
|
| But languages with stronger and more intelligent
| leadership showed what's possible.
|
| You cannot implement all the compiler optimizations for
| const and types in extensions. You need to fork it.
| MGriisser wrote:
| (I'm not sure if this still holds under a world where LLMs are
| doing the majority of writing code but this is my opinion from
| prior to LLMs)
|
| From someone who has worked mostly in Ruby (but also Perl and
| TypeScript and Elixir) I think for web development, a dynamic
| language with optional types actually hits maybe the best point
| for developer productivity IMO.
|
| Without any types in a dynamic language, you often end up with
| code that can be quite difficult to understand what kinds of
| objects are represented by a given variable. Especially in
| older poorly factored codebases where there are often many
| variations of classes with similar names and often closely
| related functions it can feel almost impossible until you're
| really familiar with the codebase.
|
| With an actual fully typed language you're much more
| constrained in terms of what idioms you can use and how you can
| express and handle code by the type system. If you're not adept
| or knowledgeable about these things you can spend a lot of time
| trying to jam what you're attempting into the type system only
| to eventually realize it's impossible to do.
|
| A gradual type system on top of a dynamic language gets you
| some of the best of both worlds. A huge amount of the value is
| just getting typing at function boundaries (what are the types
| of the arguments for this function? what is the type of what
| it's returning?) but at the same time it's extremely easy to
| just sidestep the type system if it can't express what you want
| or is too cumbersome.
| shevy-java wrote:
| > the best point for developer productivity IMO.
|
| That is a fair opinion. My opinion is different, but that's
| totally fine - we have different views here.
|
| What I completely disagree with, though, is this statement:
|
| > Without any types in a dynamic language, you often end up
| with code that can be quite difficult to understand what
| kinds of objects are represented by a given variable.
|
| I have been writing ruby code since about 22 years (almost)
| now. I never needed types as such. My code does not depend on
| types or assumptions about variables per se, although I do,
| of course, use .is_a? and .respond_to? quite a lot, to
| determine some sanitizing or logic steps (e. g. if an Array
| is given to a method, I may iterate over that array as such,
| and pass it recursively into the method back).
|
| Your argument seems to be more related to naming variables.
| People could name a variable in a certain way if they need
| this, e. g. array_all_people = []. This may not be super-
| elegant; and it does not have as strong as support as types
| would, but it invalidates the argument that people don't know
| what variables are or do in complex programs as such. I
| simply don't think you need types to manage this part at all.
|
| > Especially in older poorly factored codebases where there
| are often many variations of classes with similar names and
| often closely related functions it can feel almost impossible
| until you're really familiar with the codebase.
|
| Note that this is intrinsic complexity that is valid for ANY
| codebase. I highly doubt just by using types, people
| automatically understand 50.000 lines of code written by
| other people. That just doesn't make sense to me.
|
| > With an actual fully typed language you're much more
| constrained in terms of what idioms you can use
|
| I already don't want the type restrictions.
|
| > A gradual type system on top of a dynamic language gets you
| some of the best of both worlds.
|
| I reason it combines the worst of both worlds, since rather
| than committing, people add more complexity into the system.
| mrinterweb wrote:
| The times I've been bitten by type safety issues is far
| less than the hassle of maintaining types. Seriously, it is
| a much smaller issue than people make it out to be. I will
| say that I do get bitten by the occasional `NoMethodError`
| on `nil`, but it really doesn't happen often. Since ruby is
| very dynamic it is hard to say how many of those errors
| would be caught even with type annotation. I also don't
| find myself needing to write specs to cover the different
| cases of type checking. For me it is a tradeoff with
| productivity.
|
| That said, I do like it when an LSP can show some nice
| method signature info, and types are helpful in that way. I
| think it depends. At the surface level, I like some of the
| niceties that type annotations can bring, but I've seen how
| tricky defining more complex objects can get. Occasionally
| I would spend way too much time fighting types in elixir
| with dialyzer, and I've often not enjoyed TypeScript for
| the verbosity. So I understand the cost of defining types.
| To me, the cost often outweigh the benefit of type
| annotation.
| sroerick wrote:
| I fully agree with this. I'm building a site in OCAML,
| and I just this week spent 90 minutes debugging some
| weird error I didn't understand because an implicit type
| was being pulled through in a global context. It was
| pretty irritating.
|
| Maybe this isn't a fair comparison, since I'm pretty new
| to OCAML and I'm sure an experience developer would have
| seen what was happening much quicker than I would have.
| But I'm not sure I spent 90 minutes TOTAL on type errors
| doing Python web dev.
|
| Maybe I'm exaggerating, and I probably just don't
| remember the first time I hit a type error, but my
| experience with type errors was that I would very
| occasionally hit them, and then I would just fix the type
| error. Pretty easy.
| vidarh wrote:
| I would strongly oppose mandatory typing for these
| reasons, but I'm very happy to have _stable_ _low level_
| libraries add type annotations.
| mrinterweb wrote:
| When I'm writing code that will be distributed to other
| devs, I feel type annotations make more sense because it
| helps document the libraries and there is less ambiguity
| about what a method will take. As with everything, "it
| depends"
| dajonker wrote:
| Well said. There are many problems you have to deal with
| when writing code and type annotations only solve one
| particular kind. And even type annotations can be wrong:
| when you're dealing with data from external sources,
| dynamic languages like Python, JavaScript and Ruby will
| happily parse any valid JSON into a native data structure,
| even if it might not be what you specified in your type
| hints. Worse yet, you may not even notice unless you also
| have runtime type checks.
|
| The kind of messy code base that results from (large)
| numbers of (mediocre) developers hastily implementing hacky
| bug fixes and (incomplete) specifications under time
| pressure isn't necessarily solved by any technical solution
| such as type hints.
| cosmic_cheese wrote:
| > Without any types in a dynamic language, you often end up
| with code that can be quite difficult to understand what
| kinds of objects are represented by a given variable.
| Especially in older poorly factored codebases where there are
| often many variations of classes with similar names and often
| closely related functions it can feel almost impossible until
| you're really familiar with the codebase.
|
| One of the worst parts of exploring an unfamiliar codebase
| written in a language without type labeling is tunneling
| through the code trying to figure out what this thing you see
| being bounced around in the program like the a ball in a
| pinball machine _actually is_.
| sethammons wrote:
| Even in functional Elixir with immutability, I had to jump
| to various callsites to understand what was being passed in
| and what I could actually do. Pinball is apt. Types
| drastically reduce pinballing. The larger the codebase, the
| more pinball.
| jweir wrote:
| This is our experience. We have added Sorbet to a 16 year old
| Rails app. It is a big win in avoiding errors, typos,
| documentation, code completion, fewer tests are required,
| etc.
|
| And the LLMs take advantage of the types through the LSP and
| type checking.
| zingar wrote:
| I'd love to hear from you or someone in your shoes: what
| are some patterns or examples of tests that are made
| redundant by types?
|
| "It has a field of type X" has never been a useful test for
| me, my tests are always more like:
|
| "if I send message X I get return value or action Y"
|
| ... with my admittedly limited experience of types I don't
| see how they replicate this.
|
| Therefore it looks like I'd only be "replacing" tests that
| I'd never write in the first place.
|
| What am I missing?
| ivell wrote:
| One of the big advantages of types is documenting what is
| *not* allowed. This brings a clarity to the developers
| and additionally ensure what is not allowed does not
| happen.
|
| Unit tests typically test for behaviours. This could be
| both positive and negative tests. But we often test only
| a subset of possibilities just because how people
| generally think (more positive cases than negative
| cases). Theoretically we can do all those tests with unit
| testing. But we need to ask ourselves honestly, do we
| have that kind of test coverage as SQLLite? If yes, do we
| have that for very large codebases?
| zingar wrote:
| Just to clarify, are you saying SQLLite is a good example
| that we should emulate?
| michaelbuckbee wrote:
| SQLite is known for having a lot of testing. Per their
| docs around 600x as much test as application code.
|
| https://sqlite.org/testing.html
| sethammons wrote:
| First one that pops to mind is some old python code; the
| parameter that came in on some functions could be a
| single string or a list of them. Lots of bugs where
| arg[0] was a character rather than a string. So tests had
| to be written showing both being passed in.
| jweir wrote:
| We have some tests that ensure the interface is correct -
| that the correct type of args are passed say from a batch
| process to a mailer and a mail object is returned.
|
| For these tests we don't care about the content only that
| something didn't get incorrectly set or the mailer
| interface changed.
|
| Now if the developer changes the Mailer to require a user
| object the compiler tells us there is an error. Sorbet
| will error and say "hey you need to update your code here
| and here by adding a User object"
|
| Before we would have had test coverage for that - or
| maybe not and missed the error.
| rajangdavis wrote:
| I have been programming with Ruby for 11 years with most of the
| time in a professional context. It's my favorite language :).
|
| I don't care much for types, but it can be useful with denser
| libraries where IDE's can assist with writing code. It has been
| helpful in my professional life with regards to typed Python
| and Typescript.
|
| One potential example that would be interesting is utilizing
| types for reflection for AI tool calling, the python library
| for Ollama already supports this[0].
|
| It would make it easier to use such tools in a Ruby context and
| potentially enhance libraries like ruby-llm [1] and ollama-ruby
| [2].
|
| [0] https://docs.ollama.com/capabilities/tool-calling#using-
| func...
|
| [1] https://rubyllm.com/
|
| [2] https://github.com/flori/ollama-ruby
| Lio wrote:
| DSPy.Rb uses static Sorbet types if that's what you're
| looking for.
|
| https://github.com/vicentereig/dspy.rb
| rajangdavis wrote:
| This is really neat, thank you!
| zem wrote:
| the overall field is known as "gradual typing", and it is an
| attempt to combine some of the benefits of both static and
| dynamic typing (or to put it more accurately, to explore more
| of the benefits and tradeoffs on the static to dynamic
| spectrum). in the "type checkers for ruby/python/js" part of
| the spectrum what you are trying to ask is "how much static
| type safety can I add without giving up the power of the
| dynamic bits", so for instance you have code that generates
| classes as runtime (not really compatible with a strictly
| static type system in the most general case), but specific very
| common uses of code generation, like python's dataclasses, have
| support within the type checker.
| shevy-java wrote:
| That still has not really explained why they (those who
| propose that) need types in ruby specifically. Whether python
| has it or not is not relevant because it is another language.
| The argument that "language xyz has it, so ruby needs it",
| can be compelling, but does not necessarily have to be
| compelling. It needs to have a use case for ruby in and by
| itself. I don't see that intrinsic use case.
| zem wrote:
| the argument is not "some other language has it so we
| should", the argument is "static type checking is very
| useful even if it is not 100% strict, and ruby's lack of
| syntactic support for type annotations makes them clunky to
| use, so here's an enhancement that adds them".
|
| the intrinsic use case is that your code is often
| implicitly statically typed, even if the language itself
| doesn't enforce that, so it's nice for tools to check it
| for you. this gets more and more useful the larger your
| codebase gets; python and javascript have shown that in
| practice.
|
| and note that people have already written type checkers for
| ruby, they are just much less pleasant to use because there
| is no nice way to express the types you would like to
| check/enforce.
| resonious wrote:
| I work in Ruby a lot on large/old projects. I think the
| main reasons are: people nowadays are very dependent on
| editor intellisense, and "undefined method ... for nil"
| errors in production are very frustrating.
|
| That said, I am actually in the "don't want types in Ruby"
| camp. Intellisense isn't as needed if you're good at using
| irb (the repl). And the dynamism makes it super easy to
| write unit tests, which can give you back a lot of the
| guarantees you'd otherwise get from static types. Most
| importantly, a lot of the fun in Ruby comes from the
| ability to make nice DSLs and aggressively metaprogram
| boilerplate away.
| lofaszvanitt wrote:
| Religious coders spreading their religion.
| shevy-java wrote:
| I agree somewhat, but I'd rather call it their brain
| adjustment than a religion though.
|
| I think about 99% of people who suggest to slap down types
| onto dynamic languages have already been using types since
| decades, or many years, in another language. Now they switch
| to a new language and want to have types because their brain
| is used to.
| t-writescode wrote:
| Nah. 99.9% of the people who wanted the addition of
| DryStructs to a codebase I worked on wanted it because
| they'd been bit, repeatedly, by someone sending one kind of
| object into a function rather than what the function
| accepted and it just not getting caught.
|
| A robust type system allows you to make "compiler errors"
| out of runtime errors. One of these takes *way more tests
| to catch* than the other. I'll let you guess which.
| ReflectedImage wrote:
| Nah that's just a lack of understanding in the role of
| unit tests in dynamically typed languages.
| shevy-java wrote:
| Yeah. I have the same question and none of the type addicted
| folks could answer that. The explanations usually boil down to
| "I used C, so now I need types in other languages too". That's
| like 90% of the explanations you can see.
| CodingJeebus wrote:
| Being able to retroactively apply type definitions to a
| system can be helpful for large legacy application
| refactoring where simply choosing a type-safe language is not
| an option.
| cloverich wrote:
| I have two genuine, straight forward answers for you. One, I
| have an important codebase written in a non-typed language,
| that is heavily developed still. So being able to add types
| to it (assuming I / team prefer that) is nice. Second is, I
| much prefer working in typed language, but company forces X
| language(s) (say, Ruby, Python, etc). Now I can use types
| (which I much prefer), and not change language (they prefer).
| Those are both real life examples. Third is hypothetical, but
| perhaps some people starting without types decide they like
| them later and want to dip their toes on. Most of these
| languages now offer incremental types for people to try them
| out.
| atomicnumber3 wrote:
| In large - and honestly even medium - and honestly-honestly
| even _not-small_ python projects, you often end up losing track
| of what stuff is.
|
| At one of my jobs, i was often plagued by not knowing if "f" -
| short for file, naturally, that part is fine tbh - was a
| string, an io-like thing, a path object, a file object, or
| what-have-you. Sure sure, some argue this is the magic of
| python - just try to do whatever you want to it, and if it
| doesn't work, throw an error - I know I know. I'll tell you
| that's all really cool until you have 8 different people
| passing around 8 different types and you're just trying to have
| the darn program not crash and also not print logs like "could
| not snafucate file: [whatever str/repr comes out when you
| print() an IO object]". And this isn't one of those cases where
| being able to shrug at the type is like, buying you anything.
| It's just a damn file.
|
| So, when python's types came out, I started going in and type
| hinting f: str where i found it and could determine it was a
| string. (and various other things like this - obviously f is
| just an example). And suddenly after enough of this, we just
| stopped having that problem. Coworkers thanked me when they saw
| me in the diffs adding them. People just passed in strings.
|
| I'll also add that in most programs, most types are just
| primitives, built-in collections, and structs composing those
| two. So while it's quite nice yes that you can do crazy
| backflips that would simply not work in more rigidly typed
| languages, often I do want to just reassure everyone that yes,
| please pass in a str for "file". And if i've typed it as str|IO
| then do feel free to also pass in an IO. It just lets me talk
| to the other programmers in the codebase a lot more easily. I'm
| not trying to enforce correctness of types necessarily. I'm
| just trying to communicate.
| yxhuvud wrote:
| Honestly, that just seems like a case that would just as well
| be solved by better naming. Get a linter, tell it to forbid
| one letter names, and then enforce naming that isn't idiotic
| when doing pull requests.
|
| But yes, there are multiple ways to solve communication
| problems.
| t-writescode wrote:
| Ruby provides a lot of really nice libraries; and Ruby on Rails
| - *especially its ActiveAdmin infrastructure* is best-in-class
| for "build something stupid-fast". Legitimately, I'll spend a
| day or so per-page on making administrative sites that do a
| 1/10th of what ActiveAdmin does in like 2 lines. And AA does it
| much prettier, too.
|
| I write in Kotlin for myself, and Ktor and React or Ktor and
| Htmx + SolidJS, for web stuff; but those are decisions I made
| for myself, (edit: and) I know what it's costing me to not have
| the raw convenience that is Ruby's Active Admin infrastructure,
| among other things, I'm sure.
| satvikpendem wrote:
| A bunch of companies started a decade or two ago and became
| very successful using the dynamic language du jour back then,
| and now they're facing issues with said dynamism, so they
| introduce types to fix those issues, see Meta with Hack over
| PHP and Stripe with Sorbet over Ruby. The point is not for new
| users, it's for existing users to improve their development
| environments.
| elliotec wrote:
| Are they _solving_ these issues of dynamism with typing? What
| other issues does it introduce?
| satvikpendem wrote:
| Yes they are. Issues with typing on top is that it's not
| necessarily always robust enough, and not every company has
| the resources or premier language developer at the helm
| like Microsoft's TypeScript's Anders Hejlsberg.
| plaguuuuuu wrote:
| whole lotta companies moving from ruby monoliths to ts
| distributed systems
| Lio wrote:
| Whole lotta companies regret doing that.
|
| Take a working system and rewrite it as a series of
| separated network services that never quite implement the
| full original functionality in a new, trendy language
| just because.
|
| It was a fad that new broom CTOs were keen on 5 years ago
| and I've seen a few companies killed by that decision.
|
| There's so much unnecessary added complexity in running a
| distributed system of ts micro-services compared to a
| monolith. You need to be honest about that.
| burnt-resistor wrote:
| A large preponderance of the former mindshare of Rubyists in
| the heyday moved on to other platforms. There's a metric
| crapton of unsupported and broken stuff. Plus, there are few/no
| assurances of safety or performance as there are in statically-
| compiled environments because of the narrow focus on
| "development happiness" without prioritizing much else. Also,
| rubygems has governance issues that spawned gem.coop and
| numerous supply-chain vulnerabilities as there's no mandatory
| cryptographic package signing and public key management. Oh,
| and it's not reputation but the unprofessional and unwelcoming
| groupthink and inflated egos expressed in real interactions get
| in the way and turn people off.
| innocentoldguy wrote:
| I have the same question. I've been in the software industry
| since the early 90s and I've seen the "static types are the
| best thing since sex" fad fade in and out repeatedly during
| that time.
|
| Having used plenty of strongly-typed and dynamically-typed
| languages, I really can't say strong typing has had any effect
| on me whatsoever. I honestly couldn't care less about it. I
| also can't remember ever having a type-related bug in my code.
| Perhaps I have an easier time remembering what my types are
| than others do. Who knows?
| webstrand wrote:
| I like to think of typescript, pycharm, and whatever consumes
| t-ruby as, effectively, type-directed linters. The types are
| advisory only at runtime, so the full power of the dynamic
| language can be used. But at compile time the type can be
| checked and verified (insofar as they correspond correctly to
| the types at runtime).
|
| So the reason to add types to python/ruby is that switching to
| a statically typed language you lose power and expressiveness.
| But if you use a type-directed linter, you can prevent many of
| the common errors writing in a dynamic language.
| nurettin wrote:
| > what is the point of the recent wave of types for python,
| Ruby, and similar languages?
|
| Code that doesn't integrate directly with wires (controllers,
| active record, websocket, etc)
|
| IMO This is for complex, well refactored, testable code that
| provides a business layer. Coding larger projects like depot
| management, shipment, order management, middle frequency
| trading, customs all benefit from types and IDE help. Types
| basically scale the language beyond just filling in the blanks
| in your framework. You can get pretty far doing that, but not
| far enough. That's why all ruby based companies push for type
| systems. They know the pain of not knowing what to pass, or
| refactoring code that allows a parameter to be multiple types.
| serial_dev wrote:
| Having to support legacy systems with 15y+ development where
| the system works but you wish you didn't have to spend so much
| effort figuring out types?
|
| Or maybe you are an expert with a framework, you are very
| productive with it, you know the tricks, but you wish it had
| types support so maintaining these systems would be easier.
|
| Picking a "better" language or learning a framework in another
| language is not always a pragmatic choice.
| ReflectedImage wrote:
| Type free languages like Lisp, Python and Ruby have faster
| software development times than languages that use types.
|
| The developers who are using the statically typed languages,
| which are slower to develop in, with are being pushed to use
| the faster languages.
|
| But those developers don't know how to code in type free
| languages. So they attempt to add the types back in.
|
| This of course reduces the software development speeds back to
| their previous speeds.
|
| This means the whole thing is basically folly.
|
| If you want a real example you can take a look at Turborepo,
| which in weakly typed Go took 1 developer 3 months to develop
| and has 20,000 lines of code. The direct port to Rust took a
| team of developers 14 months to develop and has 80,000 lines of
| code.
|
| Exact same program but the development costs went up
| proportionally to the increase in the strength of the type
| system.
|
| There are plenty of developers out there who have only used
| static typing and don't understand it comes with massive
| software development costs compared to it alternatives.
|
| If you are developing a SaaS and you use duck typing, unit
| tests and micro-services. You will get to market long before
| your competitors who don't.
| coolgoose wrote:
| You are comparing apples to oranges, and go is pretty strong
| typed
| ReflectedImage wrote:
| I'm comparing a program with itself.
|
| Go only has basic types and interfaces to emulate duck
| typing (structural typing). The type complexity in Go is
| rather on the low side of things.
| pie_flavor wrote:
| This is junk. Writing a type annotation takes basically zero
| time, then saves you time by preventing the runtime error
| because you forgot which variable was which, then saves you
| more time by autocompleting the correct list of valid methods
| when you hit dot.
|
| Acting like Go is comparable to JS is ridiculous; Go's type
| system is the only kind of type system needed in Ruby. Rust
| is a staggering outlier in complexity. And the Turborepo port
| took a long time specifically because they tried to port one
| module at a time with C interop between the old and new
| codebases, which massively slows down development in any
| language, especially Go. This is just about the most
| dishonest 'example' you could have picked.
|
| Either that or you are saying 'weakly typed' to mean type
| inference in `var := value`, in which case (a) Rust has that
| too and (b) that's not what the debate is about, nobody is
| against that
| ReflectedImage wrote:
| Making the type annotations pass restricts you to writing
| more bloated and verbose programs in general.
|
| Stating that A is an integer isn't much of a issue but once
| you get a reasonably complex program and A now has a
| compound type made of 5 parts, it really does slow you down
| and it really does make you write considerably worse
| programs for the sake of passing a type checker.
|
| Any commercial code will need to be unit tested so there is
| no time saving from finding runtime errors earlier and an
| any good IDE will detect the same errors and provide you
| with the same auto complete automatically for free without
| any type annotations at all. These are problems which exist
| solely in your head.
|
| 1 developer vs a whole team of developers. I think you need
| to face the facts.
|
| There are studies comparing old dynamically types languages
| against statically type languages. They always show
| approximately 1/3 of the lines of code being used with 3x
| faster development times in the dynamically types
| languages. This isn't some new discovery.
|
| Well even Python is strongly typed but for the sake of this
| we are discussing type complexity.
| Hasnep wrote:
| It seems like your main gripe is that writing the type
| annotations slows you down, so I'd be interested to know
| what you think of languages like OCaml, Elm, Gleam or
| Roc. These are languages which never (or almost never)
| require any type annotations because the compiler can
| always infer all the types. Most people using these
| languages tend to add type annotations to top-level
| functions anyway though.
|
| It seems to me that this is equivalent to a language
| without a type checker that automatically generates a
| unit test for every line of your program that tests its
| type.
| rurban wrote:
| The default type is always any (or dynamic, as some call
| it). No need to type everything. Usually you type just
| some args. Not even locals.
|
| And some types can be inferred by the compiler, as e.g.
| for new instantiators. Or array, int, str convertors.
| sethammons wrote:
| I have experience that I think most don't. My experience says
| you are very, very incorrect.
|
| In the past couple of decades I have been through a couple
| IPOs, a couple of acquisitions, and have been in engineering
| leadership roles and slinging code in half a dozen different
| shaped eng/dev cultures.
|
| In every case, static typing makes teams faster and gradual
| typing was a pain with potential payoffs that were muddy.
| Gradual typing is a shitty bandaid and so are type
| annotations.
|
| I have migrated no less than 30 systems from various
| languages to Go across different companies, divisions, and
| teams. Mostly PHP, ruby, perl, python. Didn't migrate the
| elixir but I would have if given the opportunity.
|
| In every single case, the team started delivering software
| faster. Prototypes became faster with the sole exception of
| prototype admin crud panels which we have needed like twice
| out of the nearly three dozen services I have worked on
| migrating. And super dynamic json can be a pain (which I
| blame not on problem spaces but on less thought out dynamic
| typed solutions offloading their lack of design onto
| customers via randomish response bodies).
|
| When programs/applications get larger, the complexity tries
| to combinatorially expand. It can quickly outgrow what newer
| team members can juggle in their head. Type systems take some
| of that away. They also take away tests that are there due to
| lacking types. "What if this is a string, or list, or number"
| isn't a question you ask, nor is it a test you write and
| maintain.
|
| When everything fits in your head, dynamics types are
| freeing. When it doesn't fit in your head, tooling helps.
|
| Even smaller programs benefit. The dozens of teams I have
| personally witnessed don't find adding a type as a slowdown -
| they see whole test cases they can ignore as impossible to
| compile.
| dudeinjapan wrote:
| Two reasons.
|
| First, YJIT/ZJIT do much better when they know the type
| signatures of methods. You pay a performance penalty for
| implicit polymorphism, e.g. using a mix of types (Integer,
| Symbol, String) etc in the same method argument.
|
| Second, from my experience with Typescript, as much as I
| naturally dislike type declarations, I find it does help LLMs.
| Having strongly typed libs/gems and being able to mix in
| untyped app code would be a nice balance.
| tekknolagi wrote:
| YJIT and ZJIT don't use method annotations.
| dismalaf wrote:
| > First, YJIT/ZJIT do much better when they know the type
| signatures of methods.
|
| The running interpreter knows the type of objects. Ruby isn't
| untyped.
|
| The annotations do nothing for the interpreter.
| drdaeman wrote:
| If you don't specify types explicitly they have to still exist
| somewhere: in someone's head (in oral tradition of "Ah, yea,
| those IDs are UUIDs, but not those - those are integers"), or
| denoted through some customary syntax (be it something more
| formal like Hungarian notation, or less so - suggestive
| suffixes, comments, supplementary documents).
|
| They still exist at runtime, and people who work on the
| codebase need to somehow know what to expect. Having a uniform
| syntax helps to formalize this knowledge and make it machine
| understandable so it can assist developers by providing quick
| hits and preventing mixups automatically (saving attention/time
| for other matters).
|
| Types may be rarely important for local variables, but they
| matter for API contracts.
| procaryote wrote:
| It's a way to dig yourself out of the hole without a full
| rewrite, and with a smaller retraining effort for your
| developers.
| viraptor wrote:
| Existing ecosystem. As a random example, there's AWS SDK for
| ruby and python, but not for crystal and mojo. And if you want
| good compatibility, you're not writing that one on your own.
|
| You could use an entirely different language of course, but
| that involves other changes and compromises.
| happymellon wrote:
| Those who hate Java and C# without understanding are doomed to
| recreate them.
| Fire-Dragon-DoL wrote:
| It is desirable to have types at the entrypoints and at IO
| usually. Even rails has validations and SQL has schemas , or
| there are file formats
| rajangdavis wrote:
| If it is at all possible, it would be nice to have a little bit
| better support for metaprogramming namely around `define_method`
| and supplying a typed lambda or block for the dynamic method. I
| can see why this would be a pain to implement, so I don't expect
| it :).
|
| Otherwise, I think in terms of typed Ruby, this is an incredible
| undertaking with very well written documentation. Thank you for
| making this library, I think there's a lot that the Ruby
| community can benefit from with it. Cheers!
| jrochkind1 wrote:
| Wait, what happens if you want keyword arguments?
| t-writescode wrote:
| keyword arguments are, internally, syntactic sugar over a hash.
| It probably doesn't easily work with typing the explicit values
| of a raw hash
| anamexis wrote:
| This hasn't been true since Ruby 3.0. Keyword arguments are a
| core language feature with their own semantics.
| t-writescode wrote:
| Oh huh, TIL. Thanks for sharing!
| Dan42 wrote:
| Yeah, it doesn't work with keyword arguments. In the playground
| I tried a simple keyword with default value, and it converted
| to the wrong thing, as if "someone" was a valid type.
| def greet(name: "someone"): String "Hello, #{name}!"
| end
| ximus wrote:
| The obvious thing that comes to mind when looking at their
| spotlight example.
|
| However, no mention of this basic head scratcher in the docs.
| :rolling_eyes:
| anamexis wrote:
| It would seem that in T-Ruby all arguments are keyword
| arguments, although they don't really spell this out.
|
| https://type-ruby.github.io/docs/learn/functions/optional-re...
| nitza wrote:
| Their docs say that something like:
|
| `def greet(name: String, greeting: String = "Hello"): String`
|
| will work for kwargs with default values -- https://type-
| ruby.github.io/docs/getting-started/understandi...
| Lio wrote:
| I think they've missed a trick there, they could have used
| `|` like low-type does.
|
| e.g. def greet(name: String | "Hello"):
| String
|
| I know it's all subjective but I think that reads better and
| it's valid ruby.
|
| To be honest low-type with a static analysis tool would be my
| favourite syntax for this.
|
| https://github.com/low-rb/low_type
| jrochkind1 wrote:
| That example is for positional args with default values,
| according to the example usage: `greet("Alice")`. Can't find
| ruby-style keyword args example, with or without default
| values. maybe no kw args in t-ruby?
|
| Or wait, found examples that claims to be keyword arguments,
| but you define them just the same? I'm confused.
| https://type-ruby.github.io/docs/learn/functions/optional-
| re...
| jhealy wrote:
| interesting idea, good on them for trying something different in
| the Ruby ecosystem.
|
| The website is quite extensive, but the gem only has ~1.5k
| downloads. It's presumably very early on the adoption curve
| shevy-java wrote:
| def greet(name: String): String "Hello, #{name}!"
| end
|
| Yep - looks like utter s...
|
| I understand that many programmers come from languages where
| their brain has been adjusted to necessitate and depend on types.
| And they get help from the compiler in capturing some errors. But
| it is the wrong way to think about programs and logic. I'd wish
| these guys would stop trying to ruin existing languages. Go add
| types somewhere else please.
|
| Note: I also use java, so I am not against types per se. I am
| against a want-on need to slap down types onto everything and
| your Grandma, merely because your brain (of type afficionados)
| needs them for survival.
| sroerick wrote:
| I'm sad you're getting downvoted. This is objectively uglier
| Ruby code. Ruby is a gorgeous language, and aesthetics is
| seemingly not allowed in the conversation.
|
| I'm not convinced that the time savings of types exist at all,
| but even if it took twice as long to do anything with types,
| there is a completely valid argument that "it's worth it to
| look at nicer code".
| nurettin wrote:
| I want to agree, but in this current form, gp comes off as an
| emotional gatekeeper rather than someone with valid points. I
| think there are strong arguments for both sides. One off
| scripts with types is bs. Glue code with types, almost bs.
| Code close to the wire, typing those can be a pain with no
| gains. But business logic? Large code bases? You can pry*
| types from my cold dead hands.
| nurettin wrote:
| This could be interesting, but do you have arguments other than
| "stop ruining muh languages" or "u r dumb"?
| koteelok wrote:
| Don't show this to DHH
| omarqureshi wrote:
| I don't programme much any more but the whole beauty of Ruby that
| it pretty much heavily relies on #respond_to? / duck typing and
| thus you don't rely on types or class checking at all.
| dymk wrote:
| Most ruby code isn't written like that - it's written like most
| static languages, where objects conform to interfaces / traits
| / type classes / pick your poison. The community is shifting
| towards explicitly specifying and statically checking types
| now. rbs and sorbet are a testament to this.
|
| I wouldn't say it's really a beauty of the language, it may
| have been the original design intent but time has shown what's
| actually maintainable.
| zingar wrote:
| I don't think the existence of a library to do something is
| evidence of the community shifting. For me the complete
| absence of types from any Ruby I see IRL or in examples from
| conference talks, readmes etc is evidence that the community
| is uninterested despite tons of effort from big players.
| sethhochberg wrote:
| I think there's some real sample bias in that definition of
| "the community" though, because people who are passionate
| Ruby programmers giving conference talks, running meetups,
| etc are often a distinctly different group than the
| regular-old programmers making business software go 'round
| every day. The big players writing tools for bringing
| various flavors of type safety into Ruby are doing it
| because they're experiencing the pain of having lots of
| programmers working on large, complex software over years-
| long periods with the tools that Ruby gives you out of the
| box. They often employ some of those community fixtures,
| but thats not the majority of an engineering organization.
|
| The reality is that there certainly are enthusiast
| programmers who can thrive with the lightweight elegance of
| stock Ruby, but most people writing code professionally
| aren't enthusiast programmers under ideal conditions.
| Everything is always a little more distracted, a little
| less well-defined, and a little more coupled to legacy than
| anyone would want. And those are the conditions where I
| want my tools working as hard as possible, automatically,
| for me / my teams.
| systemnate wrote:
| Using #respond_to? is normally a code smell. The point of duck
| typing is exactly that it allows you to avoid checking the type
| of a class. As long as the object responds to the correct
| messages, the type does not matter.
| jaggederest wrote:
| #respond_to? is fine, it's really more #is_a? that is a code
| smell, in my opinion. As long as you're dispatching based on
| #respond_to? (i.e. "does this respond to each") by calling
| the method you're checking, when it does respond, you're fine
| as far as duck typing goes. It's when you check #is_a? and
| then dispatch based on type where things get weird.
|
| An example I always used to use was something like a method
| that could take a single item or a collection:
| def unpicky(something) if
| something.respond_to?(:each) # unpack using each
| or recurse to something.each do |item| unpicky(item) end
| else # main body end end
| rezonant wrote:
| I don't think you're really losing the ability to check if an
| object responds to a message ie a_car.respond_to?(:color) just
| because theres type annotations. And I assume the type checker
| doesnt yell if you do a_car.color after that -- or if it does
| there's surely an equivalent to Typescript's `any` to
| accomplish it.
|
| And T-Ruby apparently provides interfaces to avoid needing to
| do this at all (assuming both sides are written in T-Ruby I
| assume) https://type-
| ruby.github.io/docs/learn/interfaces/defining-i...
|
| ...which is awesome!
|
| As for authoring classes, respond_to_missing?/method_missing
| should be rare, usually in a situation where its the only way
| to accomplish something. There's never been a reason to write
| something like: class Car def
| respond_to_missing?(name, priv) [:color,
| :color=].include?(name) end def
| method_missing(name, *args, &block) if name ==
| :color @color elsif name ==
| :color= @color = args.first
| end end end
|
| Instead of class Car def color;
| @color; end def color=(value); @color = value; end
| end
|
| Or, more idiomatically class Car
| attr_accessor :color end
|
| And for that last case, T-Ruby apparently covers it with:
| class Car attr_accessor :color: String end
| anamexis wrote:
| Structural typing like this is completely compatible with the
| concept of duck typing. Indeed, it's basically doing static
| checking of duck typing.
| omoikane wrote:
| > https://type-ruby.github.io/playground
|
| The playground seems broken, I can't get it to report any kind of
| error. It seems to accept even syntactically incorrect files
| (e.g. just one unmatched closing parenthesis).
| t-writescode wrote:
| That article was way better prepared than I was prepared for. I
| like how it translates its code into Ruby's official types-in-
| headers format. Very nice.
|
| I think this is a nice way to include types into a project if you
| like it. I know when you're working on large Ruby projects - 10s
| of thousands of lines across hundreds of files - types become
| really, really helpful to figure out what on earth is happening
| where. In the past I've used DryRb and was pretty happy with it;
| but an even deeper connection, like this, looks wonderful.
|
| I'd really enjoy it, I think :)
| burnt-resistor wrote:
| Yes. The proper way of adding gradual typing like Python,
| Typescript, and other platforms have. steep doesn't work in the
| rbs camp and sorbet in the rbi camp is more powerful with static
| and dynamic analysis, but it's also painful. The half-measures
| hand-wringing of separate type files, type, checking
| fragmentation that isn't usable, and awkward magic boilerplate
| comments are signs of leadership failure. Matz ain't software
| Jesus, sorry.
| bataowt wrote:
| As someone who has been raising the concern of lack of type
| hinting in Python and Ruby since the beginning, this is a
| welcoming change with a "meh" on top. Also the whole shitshow
| with Go and generics that never made any sense.
|
| Oh well.
| rubyfan wrote:
| looks a lot like Crystal
| exabrial wrote:
| Worth mentioning is Crystal lang: Ruby, with types!
| duck wrote:
| Yeah, I think it would be great if this project made it clear
| how this compares with Crystal in terms of the syntax.
| yxhuvud wrote:
| In terms of syntax, they are incompatible. At the very least,
| crystal require more whitespace than what the examples show.
| pansa2 wrote:
| How alike actually are Ruby and Crystal? I've heard the
| similarity is only skin-deep: similar syntax but quite
| different semantics.
|
| In other words, isn't describing Crystal as "Ruby with types"
| similar to describing C++ as "JavaScript with types"?
| rezonant wrote:
| Yes, Crystal is not a superset of Ruby with all of its
| behaviors and semantics. And thus, it is great if you are
| starting fresh and don't mind foregoing the Ruby gem
| ecosystem and the popular frameworks like Rails proper.
|
| But it's not a migration path for Ruby codebases to add
| types, like the new initiatives for type annotations are.
| It's just that the syntax used by the available options has
| been somewhere between bad and downright terrifying until
| now.
| viraptor wrote:
| It's different, but close enough to not matter a lot of the
| time. As in, some constructs are not allowed but they're
| extremely rare in practice and have simple workarounds, even
| if you don't preserve the exact same usage syntax.
|
| So, you extremely rarely can run Ruby code in Crystal. But
| simple scripts are trivial to annotate. Larger apps won't
| require huge changes, but you're likely to run into
| dependencies you also need to port.
| yxhuvud wrote:
| Semantics are quite different, but the stdlib APIs are
| similar enough that it really feels rubylike, unless you want
| to use some of that dynamism in ruby. The code ends up
| looking a lot more similar than c++ compared to JavaScript.
| Lio wrote:
| Well they're similar enough for this project to work:
|
| https://github.com/wouterken/crystalruby
|
| It allows you to call crystallize on a ruby method and then
| have it recompile with crystal and called over FFI, which is
| pretty neat.
|
| It would be really cool if this trb syntax could get close to
| the crystal syntax for method signatures at least.
|
| I'd love to be able to move chucks of hot code to Crystal but
| leave everything else in ruby for compatibility with existing
| projects.
| bloovis wrote:
| As others have mentioned, Crystal is close to Ruby in many
| ways, such that some simpler code will port straight over.
| I've managed to port a large Ruby application (the sup email
| client) to Crystal, and a lot of the code just worked, but I
| still had tweak just about everything else to get it to
| compile. The hardest bits were the places that used Ruby's
| dynamic nature, e.g., constructing method names at runtime
| and then calling them with send, or creating methods on the
| fly, or data structures that mixed up types freely.
|
| Crystal's intent, as I see it, is very different from Ruby's.
| Because it compiles down to machine code in a single
| executable, it's good for making things that are fast and
| easy to deploy. I've used it to make small web services as
| well as the bigger thing I mentioned above.
| nurettin wrote:
| > Ruby, with types!
|
| "Language with ruby-like syntax" more appropriate.
| gls2ro wrote:
| > Requires learning sig block's unique DSL syntax.
|
| This is an interesting proposal. But for posterity I am going to
| critique the critique on the website about Sorbet:
|
| Sorbet is Ruby and while it has a DSL that is no different than
| any other gem providing methods or objects to use. For example
| you can define a type and assign it to a Ruby constant. Because
| Sorbet is Ruby.
|
| In general I would say any type system has its own syntax when
| you go deep into it and need more than this param has this simple
| primitive type and the method returns this simple primitive type.
| So you have to learn a DSL and the syntax of a type system.
| satyanash wrote:
| On Firefox, newlines in code blocks are broken for this website.
| This causes the page to scroll horizontally to accommodate all
| the code blocks. The code is all wrapped in a single line.
| pmontra wrote:
| Not on Firefox Android. Either they already fixed the problem
| or it's OK here. I didn't check with Firefox on desktop yet
| (Linux).
| zingar wrote:
| I don't like types in separate files but I also don't want them
| cluttering my signatures. Types in comments would be my ideal, am
| I the only one who prefers this?
|
| Edit: I see sorbet supports this as an experimental feature
| https://sorbet.org/docs/rbs-support
| rauli_ wrote:
| I remember a time in early 2000s when everybody seemed to be
| raving about duck typed languages and how awesome they are. Now
| we have separate tools for the same languages to implement
| typing.
| honeycrispy wrote:
| We were raving about new atheism too. Bad ideas come and go.
| Levitating wrote:
| Ugh more transpilers.
|
| I think low_type is a much more elegant solution:
| https://github.com/low-rb/low_type
| Lio wrote:
| The problem I see with low-type[1] is that it lacks static
| analysis to evaulate type usage before runtime and, I don't
| think, it has any support for tooling so you can't get method
| usage information in the editor.
|
| I think that static analysis could be done with an extension to
| rubocop via Prism though. Same for documention features via
| Ruby-LSP tooling.
|
| I think if they worked on those they would very quickly pick up
| support as the syntax is quite nice.
|
| Until then I think that Sorbet, possibly using RBS-Inline, is
| probably the best solution. I'd give a notable second to YARD
| annotations and Solargraph. Solargraph is a much underated
| project IMHO.
|
| https://github.com/low-rb/low_type
| Alifatisk wrote:
| We are seeing multiple attempts to Ruby with types now,
| previously we only had Sorbet and Rbs (with rbs-inline), but now
| there is also Low_type and T-Ruby. I am curious about this
| direction, this shows the language is still growing, changing and
| adapting.
|
| I've seen some mention Crystal as well, but as far as I know,
| Crystal has nothing to do with Ruby except sharing similar
| syntax. Their semantics are completely different. It's not Ruby +
| types.
| jstummbillig wrote:
| Does anyone have any actual insight into why optional typing is
| not a native Ruby feature?
| troad wrote:
| This is very cool! I like this a lot. Thank you to the poster for
| sharing this.
|
| Dynamic languages have amazing dev speed, but once code matures,
| slapping some types on that code is just plucking low hanging
| fruit. It inevitably picks up easy bugs and makes the code easier
| to read, understand, and maintain.
|
| Ruby has had no good solution to dynamic typing, for reasons well
| articulated by the linked piece. Honestly, that kept me from
| writing much Ruby recently. Every line just felt like instant
| tech debt, short of any sensible pathway to static analysis.
|
| This might just get me writing some Ruby again.
| viraptor wrote:
| I love the idea, even if the implementation is basically a
| workaround for upstream resistance. Since it's Ruby and the goal
| is to be concise and pretty, I hope they will spend some extra
| time on inferring basic things. In the example, the function is
| obviously returning a string, so dropping that explicit
| annotation would be great.
| Fire-Dragon-DoL wrote:
| I look at this and think: won't this break for
| instance_variable_set?
|
| You can't tell anything about an instance variable in ruby if it
| can be set from anywhere. Of course it's a special case
| usernamed7 wrote:
| hey this is pretty cool! very interesting concept to transpile to
| rbs.
|
| in most of my coding career (rails) i have not needed types. But
| when i was working on a large codebase with many teams, the lack
| of types was a recurring issue. now i work in a SOA and face
| different coupling challenges.
|
| But i much prefer this syntax to what RBS required.
| cpeterso wrote:
| Is there an advantage for trb code to use colons for type
| annotations like: def greet(name: String): String
|
| Instead of arrows like rbs files? Why diverge from precedent?
| def greet: (name: String) -> String
| bottlepalm wrote:
| AI has become my type checker in a way. I'm writing large Python
| apps now, and not even installing the Python IDE tools into VS
| Code. The AI assistants generate and refactor my code
| understanding the types and making it work. Same with JavaScript
| as well. AI modifies the code, I run/test it. Almost never any
| bugs related to typing inconsistencies.
|
| I'm not saying we (humans) don't need type checkers and I love
| TypeScript, but something is happening where AI might
| theoretically surpass the power of traditional type checking.
| Have the power to catch even more invalid code than the static
| analysis tools, linting tools, etc.. we have now.
___________________________________________________________________
(page generated 2025-12-27 23:01 UTC)