
Stripe is building a Ruby typechecker - thibaut_barrere
https://medium.com/byteconf/stripe-is-building-a-ruby-typechecker-d6cd7cee6abf
======
Kalium
"Why don't they just use (insert static-typed system here) instead?" someone
will inevitably ask.

"Because converting a large, complex set of living codebases from one language
to another is a non-trivial task that requires boiling any number of oceans.
This approach doesn't have that problem." comes the wiser, if less
interesting, response.

~~~
pmontra
I'm one of those people. I'm not sure I'd keep loving Ruby as much as I do now
if the majority of Ruby developers end up using the type checker and I'll also
have to. I like Ruby in part because it's strongly typed but I don't have to
lose time writing types. That was very welcome coming from C and Java in 2006.
I prefer to lose time when I pass a type that I shouldn't have passed. It
doesn't happen often (not every year) vs at every single method definition.

To understand if this project could have a future outside Stripe, how popular
is Python 3.6's optional static type declaration?

~~~
klmr
> I like Ruby in part because it's strongly typed but I don't have to lose
> time writing types.

That’s why _type inference_ exists. Static typing doesn’t imply annotating
everything manually with types. Granted, _most_ static type systems require
(or at least encourage) this but it’s not necessary everywhere (or indeed for
most usage). Annotating public interfaces with types is, I’d argue strongly,
already best practice everywhere (in languages that don’t support it in the
language, it’s done in documentation).

> To understand if this project could have a future outside Stripe, how
> popular is Python 3.6's optional static type declaration?

Or rather: How popular are TypeScript or Flow? _Very_.

~~~
fouc
Ruby has the advantage of 'duck typing', due to its strong OOP foundations.
Not quite sure what Python has that reduces the demand for static type
declaration.

I think part of the popularity of TypeScript could be down to a large
proportion of javascript coders that have a background/preference for static
typing. It could also be that certain classes of bugs are more prone to happen
in JavaScript or it's harder to debug when bugs do happen?

~~~
oelmekki
Ruby has been my first professional language and I've sticked with it for a
decade, but I never really understood duck typing before switching to Go, with
its interfaces (a type implements an interface if it implements its methods,
so we can use interface as function parameter type).

I don't get why we talk of duck typing about ruby : if I pass as parameter an
object that does not quack like a duck, nothing will prevent me to do it and
it will generate an exception when quacking. Did I miss something obvious?

~~~
vidarh
The obvious part is that Ruby does not have a distinction between "compile
time" and "runtime". As such, if you want to catch those cases, you need
tests.

Duck-typing can be boiled down to: The type of a parameter to a function is
defined by the methods that will be called on it, not by its class.

E.g. if you have:

    
    
        def foo source
          dosomething(source.shift)
        end
    

Then absent additional restrictions inferred from requirements of
dosomething(), the class of "source" is irrelevant. The relevant type
information is whether or not "source" responds to "shift".

A proper Ruby-ish type checker will need to be able to handle that, or it'll
push people to write non-idiomatic Ruby.

~~~
emodendroket
> A proper Ruby-ish type checker will need to be able to handle that, or it'll
> push people to write non-idiomatic Ruby.

It probably won't be idiomatic (maybe just add interfaces?) but I think duck-
typing is overrated anyway. Just because an object responds to a method
doesn't mean it's going to do anything like what you expect. To take a
contrived example, Array.Shift and Keyboard.Shift are probably unrelated
methods.

~~~
vidarh
You don't have that guarantee with interfaces either - you're trusting that
the developer isn't lying to you. My experience is that I've more often run
into developers that have artificially barred me from doing what I wanted by
checking for a given class, than that I've accidentally passed in something
that satisfies a given type but does something different.

~~~
klmr
> You don't have that guarantee with interfaces either

True, but you can give the interfaces/contracts proper names (or namespaces).
To use the example in the parent comment, `Array` and `Keyboard` wouldn’t
implement the same contract even if both have a `Shift` method.

------
thibaut_barrere
Not yet open-sourced, but this is definitely planned.

You can try it out there though: [https://sorbet.run](https://sorbet.run)

By the way, a number of RubyKaigi 2018 talks were dealing with type checking
(and the other were about improving performance & memory usage).

~~~
bogdanu
I had the "pleasure" of creating and integrating a parser for a custom DSL
into ACE. I've created the parser in ~3 days; it took another 3 to make it
work with ACE.

If it was up to me, I'd chose monaco editor (as the guys from mozilla did it
with their webassembly editor)

~~~
ptarjan
(author of the demo site here)

I just was looking for a quick editor for the demo, and ace seemed to work
well for this. Thanks for the pointer to manaco, I'll look at that for next
time.

Using an editor in the browser won't be the final product. We're planning on
integrating into your editor of choice instead.

------
ptarjan
Thank you so much for all the interest! We're flattered and excited to see all
the discussion about the project.

Try it out: [https://sorbet.run](https://sorbet.run)

If you would like to get in touch with us about anything, please email us at
sorbet@stripe.com.

In the presentation at RubyKaigi (which will be available online soon) we
explicitly mentioned we'd like to chat with folks trying to scale Ruby into
the millions of lines of code, or folks also working on similar typechecking
projects. Of course feel free to email even if you aren't in those groups, but
I wanted to get your attention if you were.

~~~
vidarh
One thing that springs to mind: Does it handle duck-typing? In other words,
can I specify "any object that responds to methods x and y" as the expected
type of a variable?

Because if treats classes as equivalent to types, then to me it encourages
non-idiomatic Ruby.

~~~
inopinatus
We only have the published examples to go on, but unfortunately they all seem
to assume that type means class.

If that’s borne out I could never use this library. It’d be the antithesis of
duck typing and object messaging.

------
mbesto
So you know when people ask "why does X startup have X,000 developers? what do
they do all day for a single app[0]. Here is your answer:

"Technical details: \- 9 month of work by 3 people; \- real thing, runs over
all code of #Stripe"

[https://twitter.com/darkdimius/status/1002103748875902978](https://twitter.com/darkdimius/status/1002103748875902978)

Now let's look at this from a financial perspective:

So let's say average $175k salary per employee + benefits and you're looking
at easily north of $600k to do this.

I'm not saying it's "right" or "wrong", but thats just what companies at this
scale do because they create development cultures and subsequent financial
controls that allow for indirect production software development to happen.

[0]for the record, Stripe is much more complicated than just a "single app"

------
sankha93
Any reason why existing typecheckers for Ruby didn't make the cut? There are
projects like RDL [1] which provide similar functionality. I know for certain
that people from Stripe were taking a look at it last year from the issues
they had raised.

Disclosure: I am a grad student, recently started working on RDL.

[1]: [https://github.com/plum-umd/rdl](https://github.com/plum-umd/rdl)

~~~
ptarjan
Hi and thank you for working on RDL! We do love the project and spoke with
Jeff Foster a few times last year.

We did use your standard library annotations for Sorbet and have many fixes to
them sitting in your pull request queue: [https://github.com/plum-
umd/rdl/pull/68](https://github.com/plum-umd/rdl/pull/68)
[https://github.com/plum-umd/rdl/pull/72](https://github.com/plum-
umd/rdl/pull/72) [https://github.com/plum-
umd/rdl/pull/57](https://github.com/plum-umd/rdl/pull/57) . We stopped
submitting more since these weren't being upstreamed.

Before we started our project, I evaluated rolling out RDL instead of building
our own typechecker. Trust me, I would MUCH rather use an existing project
than have to build our own, but sadly it just didn't scale to our millions of
lines of code.

I'm more than happy to chat about the details of why we didn't use RDL if
you'd like to email me at sorbet@stripe.com. Thanks again for your great
project, we're standing on the shoulders of giants.

~~~
nextos
You are embarking onto a very interesting, but tough project due to the
extremely dynamic nature of Ruby!

Have you considered the property-based QuickCheck approach? Instead of
building a type checker, you just annotate your code with properties
(preconditions, postconditions and class invariants). You can generate tests
to verify your code and also inject runtime checks to fail early in case of
violations.

In my experience, this tends to work much better on dynamic languages and it
also scales to larger codebases with heavy usage of dynamic idioms.

------
taf2
This looks really nice... i wish it was just part of the language to be able
to write ruby with type information e.g. instead of having a separate more
verbose sig method that's called before each method signature...

``` class Foo extend T::Helpers

    
    
      sig(
          # Both positional and named parameters are referred to by name.
          # You must declare all parameters (and the return value below).
          foobar: Integer,
          widget: String
      )
      .returns(Symbol)
      def foo(foobar, widget: nil)
        (foobar.to_s + widget).to_sym
      end

end ```

I'd love it if we could write this as :

``` class Foo

    
    
      extend T::Helpers
    
      def foo(foobar:Integer, widget:String:nil):Symbol
    
        (foobar.to_s + widget).to_sym
    
      end
    

end

```

Not sure the best way to handle default values... e.g. widget:String:nil is
kind of awkward... but still i'd be better this way then the additional method
call 'sig'

~~~
ptarjan
(one of the authors here)

We'd love that too! We're chatting with the Ruby folks to see if anything like
that is feasible. We experimented with lots of other syntaxes (comments,
yarddoc, .rbi files, monkey-patching stdlib classes to be callable) and the
`sig` syntax seems to be the easiest for folks to use inside Stripe.

After writing sigs for the past few months, I don't dislike it as much as I
thought I would. You get the syntax highlighting and autocomplete of your
editor, while `sig` and `T` are short enough to not feel like too much
boilerplate.

We're very open to other suggestions if you have any for other syntax
suggestions. Just email us at sorbet@stripe.com.

~~~
transfire
Tomdoc?

------
bogdanu
I know the editor is not the news, and it's used just for demo, but more info
about it: currently it's an ACE editor strapped to a wasm that performs the
checking. The integration looks more like a quick poc since it's not using an
webworker for performing the checks nor does it use the editor's markers for
errors.

------
exabrial
Is Crystal still a thing? I thought it sought to keep Ruby ease but statically
for speed and to reduce bugs?

~~~
vinceguidry
Crystal is a completely different language with a different architecture and
object model that only superficially looks like Ruby. Porting code from Ruby
to Crystal is somewhat easier than, say, porting the same code to Python, but
is still an act of porting. You can't use any kind of automated drop-in
process to rewrite Ruby code to Crystal. They're just too different.

A good type system for Ruby is very much needed. Matz himself has stated that
a type system is very much on the horizon for Ruby. Can't wait.

~~~
qop
With Ruby getting an AST, and potentially a type system in the future, I think
that ruby 3 could lend itself to bring transpiled to crystal relatively
easily, depending on exactly how much type information there is, how difficult
/ possible it is to correlate that with the AST.

Scala 3 is doing the typed AST thing, so hell, why not?

~~~
chrisseaton
> I think that ruby 3 could lend itself to bring transpiled to crystal
> relatively easily

I think for this to be tractable you'd basically have to implement a complete
Ruby interpreter in Crystal and then transpire the Ruby program to bytecode to
be run by the Crystal interpreter. So not really a meaningful or useful
transpilation any more, and certainly not fast.

Even basic things like method dispatch do not have the same semantics in
Crystal as in Ruby, so almost nothing could be tarnspiled 1-to-1.

~~~
qop
We don't know very much about what ruby 3 types will look like or what other
information we'll have.

Even a small subset of ruby being transpiled would be a useful thing for some
developers.

You're much more aware of some of the constraints here than I am, as Oracle
doesn't pay me to hack ruby for a living.

With a typed AST, there'd be enough information there to build a foundation
for a rb2cr tool. I didn't say the two languages are best friends and it'll be
a breeze.

Most of the ruby code I want to rescue isn't littered with string-based
define_method nonsense. Most of ruby I think worth saving at all is outside of
rails and exists in various tools or maybe some metasploit modules or stuff
like that. The pieces of code that utilize the grossest dynamic elements of
ruby, like define method or objectspace, that stuff doesn't need to survive.

Even getting 50% of a codebase in ruby compiled to reasonable crystal is a
much better foundation than previously purported successors (elixir, scala,
swift) can do.

If ruby gets a typed ast, I'll try and write a simple transform tool for the
simplest ruby.

~~~
chrisseaton
> Most of the ruby code I want to rescue isn't littered with string-based
> define_method nonsense.

I see what you are saying - but this is where the issue is I think. You may
not write code that does sophisticated metaprogramming, but the gems you use
are probably fundamentally based on it. Even just requiring some of the
standard library uses a surprising amount of of metaprogramming. For example
you can't load something as basic as 'fileutils' without doing a lot of
metaprogramming.

The entire Ruby ecosystem is built on metaprogramming.

~~~
qop
That's where the boundary for transpilation will lie then, but I don't
consider that to be a good enough reason to justify not trying to write a tool
like that.

I really appreciate your thought on this! I look up to your work a lot.
Sometimes I wish I had spent my career with compiler a instead of
disassemblers...

Yes, there will be a lot of ruby that can never by crystallized. Yes that
kinda sucks. So yes it's very good to explore optional or gradual for
incremental refactors and modernization. But if even 1% of ruby code CAN be
crystallized, then it's worth it to do it. Maybe not for you, but my time
isn't nearly as expensive as yours must be, so I understand your reasoning
here I think.

I don't mean to be adversarial here.

~~~
chrisseaton
Part of the reason it might be coming across as a slightly negative reaction
is that I'm passionate about implementing Ruby exactly as it is. If people
want to write in Crystal that's great it can be fast. But if people want to
write in Ruby, doing all sorts of metaprogramming, or that's the code they
actually have today and need to run in order to keep their business going,
then I want to make that just as fast for them automatically. Without telling
them to use a subset, or not to use awkward features. I want people to bring
me their insane code and I'll find a way to make it fast for them. That's the
challenge I'm enjoying at the moment.

If people are happy to use a subset of Ruby then yes it could be transpiled.
But a simple subset of Ruby should work great in the new JIT compilers we're
getting anyway, without using Crystal.

~~~
qop
I used to be happy with Ruby, but learning Scala and then Crystal really
changed my mind about where the line ought to be drawn wrt to expressiveness
and safety.

I don't and have never used the vast majority of Ruby's metaprogramming
features, but I'm the odd duckling in an equation where probably 95% or more
Ruby programmers are Rails programmers, and I am not. I mean, I can, but I
don't. That factor makes less sympathetic to the majority of Ruby users who
won't have any stake in a project like what I'm thinking about. And that's ok.
And either way, if they want to make use of all those features then they will
or maybe already have realized that Ruby already does what they want and
Ruby3's care for backwards compat surely will cater to that majority in order
to keep them on board. Metaprogramming I think is the primary style of Ruby,
and that's OK.

The Crystal team has essentially reprogrammed the way I think about how it
should feel to write good OO code. Scala did the same thing for a time, but
just the sheer pain of SBT drove me away. With Crystal, Having parametric
modules is an incredible advantage. I can write mixins essentially like traits
that specialize on some new type in my program.

I have to consider how my methods end up typing out, and that changes the way
I think about how I'm going to get from here to there. With Ruby, I really
like that left-to-right idea of chaining until I arrive at the structure I
want, and the more Crystal I write the more I realized how irritating it was
to hunt down Ruby bugs by:

whatever.tap{ |o| puts "#{o} is a: #{o.class} here" }

or even deeper with responds_to? or whatever I'm trying to figure out. With
crystal, all I have to do is look at the stacktrace, it is getting a nil where
it shouldn't be at SomeClass#some_method on line 230842349, and I immediately
can work on the bug at the source of it, instead of the tedious extra step of
finding it.

Being able to make Ruby do magic was never part of the equation that held me a
romantic captive to Ruby, it was always the succinctness. Elixir came close,
but Crystal gets me all the way there.

If nothing else, maybe I will learn something new trying to find a subset of
ruby3 that I can transpile.

I haven't read much about the new JIT, but if you're happy about it, maybe I
should stop procrastinating and find out about it.

------
leshow
There's so much unanswered here, does it handle parametric polymorphism? Does
it allow sum/product types? Is there inference? Can you bound generic types?

IMO it would be a complete waste of time to add a type system that only
prevented the most trivial of type errors: mismatching Integer and String.

------
paulddraper
Interesting choice, considering that Stripe is a massive Scala user.

Is it really cheaper to write type checking for one of the most dynamic
languages ever, than port to their other language? Seems to be strong evidence
against the "stack doesn't really matter" viewpoint.

~~~
shaneos
Yes it is. Stripe can do this with three (badass) engineers while the hundreds
of other engineers continue to build their applications in Ruby. Stripe's Ruby
code base is far larger than their Scala codebase, with each being used for
the types of uses that play to their strengths. Rewriting millions of lines of
Ruby into another language would more or less involve pausing all application
development for one to two years, which simply is not feasible.

This way, a small team of skilled engineers make this typer work, and guide
its general adoption, getting the codebase well typed over the course of
years, all the while Stripe continues to grow its product suite and further
conquer the world of e-commerce.

Twitter did a huge Scala rewrite. There are many lessons to be taken from
their lack of product velocity while doing so that the Stripe team took
onboard when making this decision.

------
masukomi
ok this is going to sound snarky but it's an honest question: Why not just use
Crystal[1]?

It's basically just compiled ruby with static types, and it can infer types
correctly in most cases without you explicitly noting which they are.

The best argument for this (instead of Crystal) is keeping access to ruby
gems.

[1]: [https://crystal-lang.org/](https://crystal-lang.org/)

~~~
parvenu74
Is Crystal a superset of Ruby where any valid Ruby project is a valid Crystal
project -- just lacking type definition? If Crystal can do that then I think
adoption of Crystal would benefit greatly.

~~~
masukomi
As @chrisseaton said, no, BUT some ruby is valid Crystal. I think it would be
more accurate to say that a subset of Crystal is valid Ruby, and a subset of
Ruby is valid Crystal.

~~~
freedomben
That's correct. You can run your Crystal programs with the Ruby interpreter,
but you can't compile your Ruby to Crystal (simple scripts usually work, but
bigger things that use use gems probably won't).

~~~
djur
You can't run a lot of Crystal code in Ruby, either. They implement keyword
arguments completely differently (Crystal does it more like Python, where all
arguments can be specified by name or position) and of course Ruby doesn't
support Crystal syntax relating to types. Crystal also has a tuple type with a
literal syntax ({1, 2, 3}) that isn't valid Ruby. But otherwise it's fairly
close.

~~~
freedomben
Thank you for the correction, I was not aware of this.

------
cpeterso
This Ruby typechecker is a similar approach to Facebook's "Hack" language,
incrementally upgrading their legacy (PHP) codebase to a new statically-typed
language instead of rewriting everything in a new language.

[https://code.facebook.com/posts/264544830379293/hack-a-
new-p...](https://code.facebook.com/posts/264544830379293/hack-a-new-
programming-language-for-hhvm/)

------
samratjp
Putting this out here in case if anyone finds it useful - I like a lot of good
ideas from Contracts.rb such as the type signature looking more expressive
(personal taste - looks Haskell/Elm ish) and support of Maybe's. Granted it's
not static but def some good ideas to steal from.

[https://egonschiele.github.io/contracts.ruby/](https://egonschiele.github.io/contracts.ruby/)

------
vemv
Typical Rails codebases already enjoy a reasonable layer of 'typing' via
ActiveRecord coercions, validations, and possibly some system that
declares/documents the types/structure of your REST API.

Also, I advocate keyword arguments (especially 'required' ones), which tend to
kill 80% of the use case of typing for dynlangs ("what's the type of argument
x?")

A meaningful test suite would hammer the last nail in the coffin.

------
ninjakeyboard
Is the idea that you would take your existing code and add typesafety to it? A
statically typed language is faster because it does type checking at compile
time and does not need to do "if string, ok else throw exception", so adding a
bunch of type checking to a dynamic language adds the development overhead
without the benefit. I suppose there is a false economy in that statement as
defects caught early save time vs late defect discovery, which in my
experience, is very common due to type issues in dynamically typed languages.

I personally prefer working with statically typed languages but I've been
working with elixir for the last 8 months or so and do not feel very compelled
by the use of dialyze (type checker) in the dynamically typed language - you
get used to the idioms and try to keep the code type-y but it seems
unidiomatic to take type safety too far in a dynamically typed language when
you don't get the performance benefits. You cover the things you're likely to
get wrong but embrace it for the sake of development speed otherwise. For a
new project the right question to ask is "why would we use this instead of a
statically typed language." I suppose for an existing project the question
this is trying to solve is "how can we reduce bugs now that we've made it to
market."

------
olingern
I was at RubyKaigi. This presentation was one of the best delivered, so kudos
to the Stripe team for all the work put into it.

A question I didn't get to ask while there is -- will there be some sort of
type sharing system introduced?

I've been a user of both Typescript and Flow (both great tools), but saw
Typescript's popularity soar because of community written types.

~~~
darkdimius
> A question I didn't get to ask while there is -- will there be some sort of
> type sharing system introduced?

Yes. This was one of goals of our talks. We wanted implementors of type
systems for ruby to start collaborating, in particular on a repository of
typed shims.

The details of how this would work out might be different. Typescript and Flow
change syntax and thus they cannot be included inline in arbitrary JavaScript
libraries. We're intentionally compatible with Ruby syntax. Thus we would like
this "repository of types for libraries" to only contain types intermittently,
until types have been accepted to upstream of respective library.

~~~
olingern
> We wanted implementors of type systems for ruby to start collaborating, in
> particular on a repository of typed shims.

I see. Do you see this being a mono-repo of types that's under a Sorbet org or
something Sorbet looks for in a gem if provided? Opening issues for a
project's types with Typescript has been somewhat painful since many live in
one repo [1].

1 -
[https://github.com/DefinitelyTyped/DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped)

------
seanwilson
Is there any discussion on why Stripe chose to write so much code in Ruby? I
would have thought for financial software where subtle bugs can have a huge
impact you would want to opt for a language with static checks. Or maybe only
a small part of the codebase requires this?

------
lettergram
I have to say, after using Stripe for a few years - I'm amazed at how well it
works. In fact, I can even create a "refer a friend" system on a rails app in
some 15 lines of code[1].

I'm excited if they can bring the same simplicity to their additions to
languages and frameworks as well.

[1] [https://blog.projectpiglet.com/2018/03/refer-friend-using-
st...](https://blog.projectpiglet.com/2018/03/refer-friend-using-stripe-
rails-15-lines-code/)

------
sandstrom
Interesting! Anyone with insight into the ruby core team know if Ruby may add
typing (optional or mandatory) in the future?

~~~
griffinheart
Was at the Kaigi and on the opening keynote Matz talked a bit about it. He
doesn't really support adding it since he feels like in 20/30+ years, advances
in technology will make writing types "obsolete".

~~~
quelltext
It's a weird argument. If it's not necessary in 30 years (I doubt it because
some of the type inference issues are simply undecidable, and that in much
simpler languages already), then the language can just opt to ignore type
annotations or merely check their consistency. Having them is great either way
for the benefit of documentation.

My take is he doesn't really like (or "get") types and feels protective of his
language, which is fair. I think Python made an interesting choice here, i.e.
provide syntax for types without semantics. The drawback there is potential
fragmentation on type system semantics.

------
lobo_tuerto
So, Sorbet is to Ruby what Dialyzer/Dialyxir is for Erlang/Elixir right?

Are they using basically the same approach?

------
emodendroket
Having done some legacy Ruby work I'll say this is sorely needed.

------
mslate
Is this analogous to mypy?

~~~
ptarjan
It is a similar idea, yes.

------
qop
I think the most fascinating thing that Ruby 3 could approach is an approach
similar to Dart 1's optional types. That way a fast unchecked mode could be
available for developing, and REPL usage, and then a separate switch could be
flicked for building a release.

Seeing the Ruby devs take compatibility so seriously is such a confidence
builder for me, either way. Ruby is such a joy to program in, and for certain
projects, Crystal fits the "square enough to go in a square-ish hole" role,
but I really miss some of the ease-of-use that Ruby has to offer.

require 'Something'

Something.new.methods.sort

I use that every single day. Crystal can't do that. Yet.

Little things like that make Ruby such a human-friendly language.

Now that we've learned our collective lesson that naive dynamic types are too
slow for big projects, I am glad to see Ruby-thinkers begin to explore the
type system space and search for something that will benefit all Ruby hackers.

I suspect that if we arrive at the point where Ruby has a gradual or optional
type system available, that refactoring some of the old Ruby tools will be
very pleasant. If or when that day comes, I know I'll devote a chunk of my own
time to try and catch the tools back up, and the rest will follow if only
there are hackers who want to hack badly enough.

~~~
Willamin
A lot of people that love Ruby and dislike Crystal seem to dislike Crystal for
reasons like what you mentioned. I'm pretty sure that you can get a sorted
list of methods in Crystal (not with the same syntax unfortunately) at compile
time in macros. I'm not sure why you would ever want to dynamically get a
sorted list of methods at runtime... unless you're adding methods at runtime.

~~~
qop
I use it in the repl for classes I'm not familiar with. I use Ruby for duct
taping a lot.

------
iamleppert
People created dynamic languages for the exact reason of not having to define
types.

Now the trend is to bolt on type checking to dynamic languages because people
don’t want dynamic behavior. Most developers I’ve encountered who seek to add
types to dynamic languages will never truly understand dynamic languages,
closures, concurrency passing or functional programming for that matter.

If you want a statically typed language, use one. Use one that was designed
for deterministic behavior and static correctness.

If you have a huge codebase in Ruby that is full of bugs and is unpredictable,
don’t blame the language or lack of types.

There are plenty of ruby codebases that are bug free and work well without
static typing. How do they exist?

~~~
Tehnix
> Most developers I’ve encountered who seek to add types to dynamic languages
> will never truly understand dynamic languages, closures, concurrency passing
> or functional programming for that matter.

I don't see how seeking to add types precludes also understanding "closures,
concurrency passing or functional programming", especially since these are in
no way foreign concepts in statically typed languages.

> If you want a statically typed language, use one. Use one that was designed
> for deterministic behavior and static correctness.

I definitely see what you're trying to say, but as I understand it, these
projects to "add types" often come on later, when the project is so big, that
it is simply less time consuming to just develop a type checker, than it is to
rewrite your entire codebase in a new language.

~~~
iamleppert
My argument is that you can always implement your own breed of type checking
either via convention (with appropriate enforcement via static analysis or
linting tools if so desired without having to run the code), or you can do
type checking at run time -- most dynamic languages have a facility to
interrogate a variable to determine its contents and you can implement any
number of tests on it as you see fit to validate it.

~~~
hderms
In practice the difference in guarantees between a static type checking system
and a runtime one are so vast that I think they're mostly incomparable.
Runtime checking is like doing most of the work of modelling a program with
static types but achieving a fraction of the benefit.

------
pg_bot
I don't understand the appeal of static typing. It always feels like I'm
adding overhead without receiving any benefits. I've worked in some fairly
large dynamically typed codebases and have never run into issues with type
errors. Static typing does not alleviate the need to test your code, which is
a more effective way of reducing bugs in your system than annotating your
methods/functions.

~~~
matchbok
Not sure I've ever heard anyone say static typing removes the need for
testing.

Types are self-documenting. Onboarding new devs in a _large_ static codebase
will be 10x easier than a dynamic one.

Coding is actually faster in statically typed projects - autocomplete works
every single time and you never have to dig into another source file to see
what objects/methods you have.

And, most modern type systems (Typescript, Swift, etc) don't have much
overhead at all with their impressive type inference.

~~~
mping
It's a double edged sword - onboard some devs on "advanced" scala code and let
me know how the 10x is working for ya. I also feel that sometimes types cause
additional congitive load - you have to mentally model the types and what they
do. OTOH I'm pretty sure most people can onboard a js project that's well
written.

I think exploratory, debug-based onboarding can be easier with poorly written
static lang codebases that dynamic, but then again depends on what convetions
are used. I don't care much about autocomplete unless I have to type
ReallyLongClassNamesThatAreSupposedToBeMeaningful; besides coding is mostly
about avoiding errors, not typing faster.

In the end, whatever floats your boat but dyn langs surely have their place.

~~~
matchbok
I've heard the "mentally model" argument a few times, and tbh I don't quite
understand it. You have to model the object regardless, either with types or
tons of extra checks to make sure that object has what you need. I've seen so
much javascript code do exactly that because the methods had no idea what they
were going to be given. The contract of static typing eases that load, I
think.

~~~
mmartinson
Ya for sure. Without getting a debugger into the application code, it
sometimes seems completely impossible to look at a piece of dynamic code
you're not already familiar with and decide if it's going to work. I've found
this especially tough during code reviews for new stuff that make heavy use of
abstractions, even when the abstractions are good.

