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?
(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.
> 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.
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.
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.
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.
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.
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.
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].
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.
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.
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.
You get the complexity and slower development times of using statically typed languages along with the bad performance of using dynamically typed languages.
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.
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.
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.
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.
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.
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.
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
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.
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.
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.)
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.
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.
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.
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?
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.
> 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.
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.
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.
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.
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.
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.
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.
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.
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.
> 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.
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.
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.
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.
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.
#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
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.
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:
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.
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.
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.
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.
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!
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.
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).
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.
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?
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.
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".
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.
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.
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?
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
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.
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?
(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.
> 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.
1 reply →
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.
5 replies →
> 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.
2 replies →
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.
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.
Are they _solving_ these issues of dynamism with typing? What other issues does it introduce?
3 replies →
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.
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
DSPy.Rb uses static Sorbet types if that's what you're looking for.
https://github.com/vicentereig/dspy.rb
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.
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.
2 replies →
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.
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.
2 replies →
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.
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.
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.
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.
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.
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.
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
1 reply →
You are comparing apples to oranges, and go is pretty strong typed
1 reply →
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.
Those who hate Java and C# without understanding are doomed to recreate them.
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.
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.)
Crystal is a cool Ruby-like.
It's a way to dig yourself out of the hole without a full rewrite, and with a smaller retraining effort for your developers.
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.
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.
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.
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?
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.
> 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.
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.
Religious coders spreading their religion.
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.
2 replies →
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.
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.
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.
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 :)
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.
Ugh more transpilers.
I think low_type is a much more elegant solution: https://github.com/low-rb/low_type
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
> 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.
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.
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.
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.
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.
#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:
Structural typing like this is completely compatible with the concept of duck typing. Indeed, it's basically doing static checking of duck typing.
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:
Instead of
Or, more idiomatically
And for that last case, T-Ruby apparently covers it with:
Does anyone have any actual insight into why optional typing is not a native Ruby feature?
Worth mentioning is Crystal lang: Ruby, with types!
Yeah, I think it would be great if this project made it clear how this compares with Crystal in terms of the syntax.
In terms of syntax, they are incompatible. At the very least, crystal require more whitespace than what the examples show.
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”?
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.
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.
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.
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.
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.
> Ruby, with types!
"Language with ruby-like syntax" more appropriate.
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!
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
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.
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).
> 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).
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.
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
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.
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".
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.
This could be interesting, but do you have arguments other than "stop ruining muh languages" or "u r dumb"?
looks a lot like Crystal
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.
Wait, what happens if you want keyword arguments?
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...
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...
I think they've missed a trick there, they could have used `|` like low-type does.
e.g.
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
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...
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.
keyword arguments are, internally, syntactic sugar over a hash. It probably doesn't easily work with typing the explicit values of a raw hash
This hasn’t been true since Ruby 3.0. Keyword arguments are a core language feature with their own semantics.
1 reply →
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:
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.
[dead]
Don't show this to DHH