Readit News logoReadit News
the_duke · 7 years ago
It's been funny to watch how more and more static type systems are getting bolted on to dynamically typed languages in recent years.

Typescript (with stellar adoption), native type annotation support in Python, Sorbet, PHP 7, Elixir + Dialyzer, ...

I wonder why there isn't a popular gradually typed language that natively allows writing both dynamic and type-safe code, allowing quick prototyping and then gradual refactor to type safety.

I guess in part because it's a big challenge to come up with a coherent type system that allows this, the bifurcation in the ecosystem, and often a somewhat leaky abstraction. Eg in Typescript you will often still run into bugs caused by malformed JSON that doesn't fit the type declaration, badly or insufficiently typed third party libraries, ....

Google's Dart is the only recent, somewhat popular language (only due to Flutter) that allows this natively - that I can think of right now.

I do think such a language would be very beneficial for the current landscape though, and projects like this show there is a clear need.

Edit: just remembered another option: Crystal. Also Julia, as pointed out below.

tptacek · 7 years ago
For whatever it's worth and without wanting to start a language war (I like Python just fine), I think Python/Ruby-style typing is a false economy for prototyping. There are a lot of things that make Go slower to write than Ruby, but mandatory typing isn't one of them. Rather, Ruby's total lack of typing makes it harder to write: you effectively end up having to write unit tests just to catch typos.

I wonder whether the perception that type safety slows down Ruby (or ES6) development comes from the fact that the type systems are bolted on after the fact.

pcr910303 · 7 years ago
I would say that dynamically-typed languages are great to prototype as they do not emphasize on being correct too much.

Being correct from day one will cause too much unnecessary friction. You (usually) don't know the entire program architecture until you make a full prototype, and even if you have a plan, there will always be some part where some unexpected consequences force you to rearchitect some parts. And since you don't know the entire program architecture you architect your program bottom-up, and most of the dynamically-typed languages allow an interactive development environment at a flexibility that typed languages can't provide.

Think about developing Python inside a Jupyter notebook, or Common Lisp inside a REPL. You turn on a REPL, open up a file, write a function, send the function to the REPL, test the function you just wrote, and when I find a mistake I can just redefine any function I would like to change. This process allows fixing mistakes on-the-fly. Typed languages don't allow this (even ones that have a so-called REPL) at this flexibility, (since they emphasize on being correct all the time), and cause too much unnecessary friction while prototyping.

Thus a need for a dynamically-typed language that can enforce types after prototyping.

steveklabnik · 7 years ago
I think about this a lot, as someone who loves Ruby and loves Rust. I think it’s because we do a bad job of looking at the total costs. It feels like you can knock something out really quickly in Ruby. And in some sense, you can! But the time you spend debugging later doesn’t get factored into the way that it feels when you’re just cranking out features.
zapzupnz · 7 years ago
I've never quite understood the notion that languages like Python and Ruby are amenable to fast prototyping. Ultimately, you wind up just having to carry complicated type information in your head rather than write it all down in your code, all whilst the compiler utterly fails to help you in any way in case your memory ain't what it used to be.

I'm sure those languages and their ilk have advantages for prototyping, but I agree, mandatory typing in other languages isn't a burden. If you already have to reason about what arguments are acceptable in functions, what objects can receive what messages and what those messages should contain, you already have typing — just inefficiently stored in short term memory.

Those who are the biggest proponents of these languages as useful for prototyping are also not the ones who rewrite their code in type-safe languages, so being able to add type annotations for the sake of their colleagues who eventually have to turn these prototypes into code upon which a team can collaborate can only be a useful thing.

nine_k · 7 years ago
Python and Ruby are extremely malleable, like Smalltalk and lisp before them. You can inspect anything, you can override / replace / proxy anything. You can use a few built-in collection types for nearly anything.

This is by design. This is great for prototyping.

These languages are to programming what breadboards and wires are for electronics.

Of course, as your system grows, you start to want static checks, or having your schematics on a PCB. But at the very start, tweaking a piece of Python code, or a breadboard, is easiest. Then, of course, you may not want to afford a a rewrite to rust, or would put your breadboard in a box and ship it :)

dragonwriter · 7 years ago
> There are a lot of things that make Go slower to write than Ruby, but mandatory typing isn't one of them. Rather, Ruby's total lack of typing makes it harder to write: you effectively end up having to write unit tests just to catch typos.

No, you don't. You need unit tests to verify behavior (values) whether or not you have static typing (except for output types with only zero or one values). Now, it's true, that having such tests also verifies, at no extra charge, things that Go’s type system would verify, but without the additional effort of type annotations. But there's no added cost there, it's a net savings.

danmaz74 · 7 years ago
Nowadays I write unit tests for any nontrivial code I create. It takes a little more time than writing type declarations, but IMHO they offer much more value.
tarsinge · 7 years ago
For prototyping sure, because the prototype might grow, but otherwise it depends on the type and scope of the project I think. For the kind of CRUD web app projects I pick Ruby for I still fail to see how I could benefits from types instead of slowing me down. I may be missing something, so I’m interested if you have any resources with concrete examples for common errors.
jchw · 7 years ago
I agree: I think most people that look at typechecking as a serious friction are thinking about it wrong; the problem is probably languages with bad ergonomics. Many people who use TypeScript actually end up using it with strict defaults for even new or toy projects - it’s too valuable to not, honestly.
pvg · 7 years ago
Wasn't that perception around long before the 'bolted on' type systems appeared? To me, it seems like some of the clunkiness and sharp edges of the type systems of commonly-used typed languages at the time - C++ and Java had a lot to do with it along with RoR enthusiasts portraying static typing as some sort of tool of oppression.
shay_ker · 7 years ago
I think it's mostly the REPL that allows for quickly spiking out things, with quick feedback. Elixir has a similar experience, but less of the warts you get with Ruby (like monkeypatching).
_hardwaregeek · 7 years ago
Unless you've used a language with a high level of strictness, i.e. OCaml/Haskell/Rust, it can be hard to see the sheer power and utility of typechecking. If someone has only used Java, they may not understand the true power of types. But if you've familiar with OCaml/Haskell/Rust, why bother writing dynamically typed code? Sure there's some niche usecases where it's more powerful, but generally you can do as much with say, Rust, or even more pragmatically, C# 8/Kotlin.

While if you've only used dynamic languages or badly typed languages, then having to deal with this stupid naggy compiler is just annoying. A big part of learning a strongly statically typed language is learning that the compiler is your friend, and that errors are good. I've noticed that a lot of people new to TypeScript try to get the compiler to shut up, often resorting to any or @ts-ignore, while more advanced users will see it as a dialogue. The compiler complains? Okay, something's wrong: Let's find the root cause here.

TypeScript took off because people had no choice but to write JS, so any benefit was better than no benefit. Sorbet was also borne out of an existing codebase. But a new language wouldn't have this lock in factor.

tomp · 7 years ago
Copying my comment from above...

I am an "expert" in static type systems (I'm familiar with Java, Scala, OCaml, Haskell, Rust, Go, TypeScript, C++ ... and keep up to date with latest type systems research like 1ML, MLsub, Liquid Haskell, ...), but I have a really hard time imagining how one would develop a statically typed library that would even approximate the usefulness and convenience (for rapid prototyping and interactive data analysis) of Python's Pandas (although if I was a betting man, I'd wager the best language to implement it in would be Scala, with it's advanced macros & almost-dependent type system).

IshKebab · 7 years ago
I don't think it is hard to see the power of stronger typing - surely everyone who has written any code in Python or Javascript has made a typo that would have been caught in a more strongly typed language?
gbersac · 7 years ago
Add scala to the list. Or any typed functionnal language.
robacarp · 7 years ago
> a popular gradually typed language that natively allows writing both dynamic and type-safe code, allowing quick prototyping and then gradual refactor to type safety.

You mention it in your edit, but Crystal has been exactly that for me. A rubyist for a decade I found Crystal to have the type system I was expecting all along.

jez · 7 years ago
Have you seen Julia?

https://julialang.org/

The first three selling points on their home page are Fast, Dynamic, Optionally Typed.

Buttons840 · 7 years ago
Meh. Julia does nothing to help me catch errors before runtime, it's no different than Python in this regard. Although it does use the types to generate fast code (and in my experience it does live up to its performance claims).

I've seen some talk of Julia doing compile time checks, maybe in the future it will?

seanmcdirmid · 7 years ago
Isn't Julia optionally dynamically typed, not optionally statically typed?

Deleted Comment

p4bl0 · 7 years ago
I'll add Racket and its variant, Typed Racket, to the list. See https://docs.racket-lang.org/ts-guide/index.html
munificent · 7 years ago
Dart isn't optionally typed any more. It's now a fully statically typed language, that also has a special "dynamic" type. That puts it in the same boat as C# and Scala, among others.

Optional or gradual typing does seem like an obvious brilliant idea from the outside. Start out dynamic when the program is small, layer in types when it grows to the point where you need them. Capture the union of both dynamically typed and statically typed users. Everyone wins!

In practice, we found ourselves in an uncanny valley where we were too typed for the dynamic typing folks, and too unsafe for the static ones. We couldn't deliver the user experience either camp expected. We learned, the hard way, that a statically typed language is not simply a dynamically typed language plus some type annotations. Everything about how you use the language is different.

---

The way you design APIs is different

Python's tuple type has a subscript operator to return an element at the given index. That's a perfectly reasonable, simple, clean API in a dynamically typed language. If you want to have statically typed tuples, that API doesn't even make sense:

   t = (1, True, "three")
   x = t[datetime.datetime.today().weekday() % 3]
What is the static type of x?

Another example: Python's list type has a sort() method. It takes an optional "key" argument that is a callback that converts each value to a key of some time and then sorts using those projected keys. If you pass a key function, then sort() needs to be a generic function that takes a type parameter for the return type of the key function, like:

    sort<R>(key: (T -> R))
But if you don't pass the key function, the R type argument is meaningless. Should it be a generic method or not?

An even gnarlier question is "What kinds of lists can be sorted at all?" The sort() method works by calling "<" on pairs of elements. Not all types support that operation. Of those that do, not all of them accept their own type as the right-hand operand. How do you design the list class and the sort() method such that you ensure you won't get a type error when you call sort()?

To handle this kind of stuff, the "best practices" for your API design effectively become "the way you would design it in a fully statically-typed language". But those restrictions are one of the main reasons people like dynamic languages.

You can mitigate some of this with very sophisticated type system features. Basically design a type system expressive enough to support all of the patterns people like in dynamically typed languages. That's the approach TypeScript takes. But one of the main complaints with static type systems is that they are too complex for humans to understand and too slow to execute.

This makes that even worse. TypeScript's type system is very complex and type-checking performance is a constant challenge. In order to let you write "dynamic style" code, TypeScript effectively makes you pay for a super-static type system.

---

User expectations are bimodal

Once you ask people to design their APIs such that they can be statically typed and then let them start writing type annotations, we observed that they very quickly flipped a mental bit and expected the full static typing experience. They expected real static safety where certain errors were proven to be absent. They expected the performance of a statically-typed "native" language.

But most optional or gradually typed languages are unsound in order to allow typed and untyped code to intermingle. That means type errors can still sneak through and bite you at runtime. It means you get none of the compile-time performance benefits of static types. Sorbet asks you to write your code with all of the discipline, restrictions, and cognitive effort of a statically-typed language. In return, it gives you the runtime performance of... Ruby.

Worse, actually, because it is checking your type annotations dynamically at runtime. It basically turns your type annotations into assertions. So you get even more potential runtime failures.

This was how Dart 1.0 worked. I used to joke that we gave you the best of both worlds: the brevity of Java and the speed of JavaScript. And then I cried a little.

---

This sounds like I'm criticizing this approach to languages. I actually think TypeScript, Flow, Sorbet, and others are a really smart solution to a very challenging problem. If you have a very large corpus of dynamically-typed code that you want to keep extracting value out of, they give you a way to do that while getting some of the benefits of types. If I was sitting on a giant pile of JS or Ruby that I had no plans to rewrite, I would absolutely use one of these tools.

But for new development, I think you're much better off choosing a modern statically typed language if you think there's a chance your program will grow to some decent size. By that, I mean C#, Go, Swift, Dart, Kotlin, etc. Type inference gives you most of the brevity of dynamic types and you'll get all the safety and performance you want in return for your effort to type your code.

If you're going to do the work to make your code typable, you should get as much mileage out of it as you can. So far, no one I know has figured out how to do that with an optionally or gradually typed language.

---

This is, of course, just my personal preference. And I'm biased because I've already walk the long painful educational road to understand static types. One of the real large benefits of dynamic types is there is much less to learn before you can start writing real code. For new users, hobbyists, or people where programming isn't their main gig, this is huge. I love that dynamically typed languages exist and can serve those people.

But my experience is that if you're a full time professional software engineer writing real production code eight hours a day, it's worth it to get comfortable with static typing and use it. The fact that basically every large software shop that had a big investment in dynamically typed languages is trying to layer static typing on now probably tells us something. Google with Closure Compiler and Dart. Microsoft with VB.Net, TypeScript, and Pyright. Facebook with Hack and Flow. Apple with Swift.

abhorrence · 7 years ago
TypeScript actually handles the first example quite well. If you simply have a heterogenous array type, the type of its members will be the union type of `number | boolean | string`.

If you’ve used a typed tuple, then the type after access is based on what TypeScript statically knows. So array[0] would be number, but array[random() % 3] would be the union type.

muglug · 7 years ago
> But for new development, I think you're much better off choosing a modern statically typed language if you think there's a chance your program will grow to some decent size.

> By that, I mean C#, Go, Swift, Dart, Kotlin, etc.

I think all of those require compilation. While I loved writing C# in a previous job, the compilation step added some small amount of friction to regular web development.

Though working with PHP requires more thought for the big-picture stuff (no PHP ORM can touch what C# offers) I find it easier to get into a state of flow when developing new features. Once I've completed a given task I can run a static analysis tool (I've made one at Vimeo, but there are others to choose from) that can automatically add most of the types I neglected to add, and can suggest more.

dharmatech · 7 years ago
> Dart isn't optionally typed any more.

Gilad was (religiously) in favor of optional types. Did he come around to agreeing with the direction that Dart has taken (i.e. full static types)?

Deleted Comment

derefr · 7 years ago
> What is the static type of x?

an anonymous (Integer | Bool | String) sum-type, of course.

cmpolis · 7 years ago
Thanks for bringing up Dart (underrated IMHO). The built-in optional typing helps with productivity and readability. There is also a great official style guide which goes over when static/inferred/dynamic typing are preferred: https://dart.dev/guides/language/effective-dart/design#types
xhubin · 7 years ago
Agreed, I really hope Dart gets more adoption now with the help of Flutter. I would especially want it to get some more back end love.
keithlfrost · 7 years ago
Clojure allows one to start with essentially untyped code, then add type declarations for efficiency and safety.
kyllo · 7 years ago
core.typed never really caught on though, what seems more popular is Schema which focuses on annotating and validating the structure of lists and maps: https://github.com/plumatic/schema
pbiggar · 7 years ago
I'm actually working on solving this problem at the moment with https://darklang.com. Our approach is to allow the quick prototyping of python via tooling built-into the editor, within a language that has strong static types (similar to Haskell or OCaml).

As an example, you never change types in Dark, you only make new types and switch over to them, so if you want to test out a type change for just one HTTP route, you can do that.

Dark also doesn't have nulls or exceptions because they're hard to reason about. The usual tools to replace them (Result and Option/Maybe types) require you to handle all the cases when you write code using them. We're allowing you to write code that doesn't handle these cases (again, using editor tooling). Instead it tells you exactly what errors can happen at every point in your code. Once you have your initial prototype/algorithm figured out, you can use that information to handle all the edge cases.

lifthrasiir · 7 years ago
> Instead it tells you exactly what errors can happen at every point in your code. Once you have your initial prototype/algorithm figured out, you can use that information to handle all the edge cases.

While I can't say much about Dark (the available blog posts [1] are shallow), I do think that the automation may be one key aspect of future programming languages. For example, when I'm thinking about gradual typing I don't only want to mix the hodge-podge unitype and actual types but also convert the former to the latter, and a large portion of the process can be automated in various ways (for example, one can track the typical runtime types that unityped variables have; the programmer can solidify compile-time types using that fact).

[1] https://medium.com/darklang

tomp · 7 years ago
Do you have any documentation?

> Dark also doesn't have nulls or exceptions because they're hard to reason about.

How do you handle OutOfMemory errors?

lillesvin · 7 years ago
> I wonder why there isn't a popular gradually typed language that natively allows writing both dynamic and type-safe code

Unless I'm misunderstanding something, PHP7 can do exactly that.

With regards to the general trend you mention about adding static-ish typing to dynamically typed languages, the opposite is also happening to some extent. I work in a medium sized company that does mainly .NET and I see C# devs use `var` a lot (in order to let the compiler infer the type instead of having to declare it explicitly). I'm not sure if the `dynamic` type is also seeing increased use, but just the fact that it was added to the language in v4 says at least a little.

I think what is really happening is that the more popular languages will sort of naturally converge as development progresses and more and more people request features. So while Mr. PHP-dev-turned-to-C# will maybe want more dynamic-ish typing in C#, Mr. C#-dev-turned-to-PHP will request more static-like typing in PHP.

yellowapple · 7 years ago
> I wonder why there isn't a popular gradually typed language that natively allows writing both dynamic and type-safe code, allowing quick prototyping and then gradual refactor to type safety.

Popularity aside, Perl 6 supports exactly this.

jjeaff · 7 years ago
So does php 7
loxs · 7 years ago
Fast prototyping without types? Meh! I need types to be able to prototype and change things really fast, knowing that it won't break.

I feel a lot more confident to prototype in OCaml/F# and then "downgrade" to an 'ordinary' language that needs more people to understand what is written, than the other way around (prototype in Python and move to something 'real' later)

I think that recent movement to put types in dynamic languages is just because of the need to fix existing projects, people are finally "getting it".

TypeScript is awesome in this regard. Almost makes JS bearable.

zeckalpha · 7 years ago
Haskell, with deferred type errors and runhaskell, is quite a dynamic language.
rlander · 7 years ago
Just to be a little pedant, Dialyzer (an Erlang success typing lib) precedes Elixir and the other static typing efforts you mentioned by many years, way before this so called “static typing renaissance”.
elcritch · 7 years ago
Another thing to point out is that (dialyzer) typespecs are extremely prevelant in both Erlang and Elixir libraries and especially the core language libraries. So not only does dialyzer precede the others, it’s become a core part of Elixir and Erlang. In contrast, mypy & sorbet appear to be largely second class tools. TypeScript though appears to have made more inroads.
nullwasamistake · 7 years ago
Type inference is where it's at. Everybody loves types when there's hardly any overhead. Typescript is the best example of this.

My theory, the first languages of most tend to be untyped. Over the years you get tired of dealing with type errors and move to more complex languages with strong typing. After a while you get tired of typing a bunch of useless crap because the compiler isn't smart enough to figure out the type for you and land in Typescript or similar

slushy-chivalry · 7 years ago
here's one more (not so popular) one: https://inko-lang.org I'm also a fan of clojure.spec, though not a substitute for a proper type system, is extremely helpful in achieving the same goal.
resynthesize · 7 years ago
> Eg in Typescript you will often still run into bugs caused by malformed JSON that doesn't fit the type declaration, badly or insufficiently typed third party libraries

there's a fantastic typescript library, io-ts (https://github.com/gcanti/io-ts), that provides the ability to declare runtime types variables that you can infer compile time types from that solves exactly this problem. it's deifnitely work taking a close look at if you want to ensure type safety at runtime for data coming from third parties.

PopeDotNinja · 7 years ago
Dialyzer is an Erlang thing, and it's been around a long, long time. That doesn't change the point your are making, and am just clarifying it a bit.
im_down_w_otp · 7 years ago
Erlang/Elixir + Dialyzer?
loxs · 7 years ago
It would be great if it had a proper IDE. That's the only major hurdle to the success of this platform.
pjmlp · 7 years ago
You forgot two of the very first ones in this regard, Lisp and Basic.

Also Dart 2.0 is strongly typed with type inference, they rebooted the type system.

kyllo · 7 years ago
Groovy is one language that is dynamic but also has an optional statically typechecked compilation mode.
vorg · 7 years ago
> Groovy is one language

Apache Groovy is two languages. The Groovy 2.x download, first released in 2012, bundles two different compilers that were both forked from the Groovy 1 compiler. Only one of them has upgraded to the JDK-7 invoke-dynamic capabilities, and the other (which hasn't) is the one actually used by Gradle and Jenkins and everyone else. Last month, the Groovy project managers at the ASF announced they were keeping the upcoming Groovy 3 as two separate languages also. The long-awaited parser upgrade from Antlr 2 to Antlr 4 is being bolted on to the invoke-dynamic compiler only -- the compiler no-one uses. They talked about Groovy 4 reverting back to a single language, but i'm guessing that's many years away because the original purpose of making Groovy be two languages in the first place was to not change the language that users actually use in any way, while simultaneously appeasing their own developers by bundling the code they wrote (invoke-dynamic bytecode generation, Antlr 4 parser upgrade, etc) in the language.

rapind · 7 years ago
I prefer how this evolves organically if / when there's a need. Once the need is proven by adoption numbers (say this ruby w/ type checking gets popular) you'll have a good idea of what people want (and any issues they might have with this implementation).
brightball · 7 years ago
I’ve found Elixir to be exactly that.
didibus · 7 years ago
As I understand, Racket seems to be the gold standard in that area.
zem · 7 years ago
stanza [http://lbstanza.org/] is optionally typed and compiles to native.
agumonkey · 7 years ago
waves and roundabout
darpa_escapee · 7 years ago
> I wonder why there isn't a popular gradually typed language that natively allows writing both dynamic and type-safe code, allowing quick prototyping and then gradual refactor to type safety.

With the addition of `var`, I think Java is that language.

simplify · 7 years ago
A fascinating part about Sorbet is it did not have to introduce any additional syntax to Ruby (unlike TypeScript, for example). This really speaks to the expressiveness of Ruby. Very cool.
SomeOldThrow · 7 years ago
The type signatures are pretty noisy to read, though, some syntax can definitely help. Maybe with Ruby 3?
est31 · 7 years ago
Was that additional syntax in TypeScript actually neccessary for type inferrence? Or is it rather to avoid API hazards when you change some internal code and suddenly the API of your library breaks because the inferred type has changed.
idle_zealot · 7 years ago
You can use TypeScript in a mode that only uses type inference and doesn't require type annotations or definitions. It works surprisingly well.
loxs · 7 years ago
It is necessary because of some limitations, but IMO it's also a great idea nonetheless. Types' names are a great documentation, one which you can't get with pure inference.

Even languages that have (close to) the best possible inference, like OCaml, still have additional syntax for defining types, because it 1. gives you documentation and 2. allows you to do things that are mathematically proven to be impossible via inference.

TS is great, and also moving really fast and becoming better every 2-3 months.

castwide · 7 years ago
Coincidentally, I announced the beta version of a Ruby type checker in Solargraph two days ago: https://github.com/castwide/solargraph/issues/192

It has a few overlapping features with Sorbet, with one major difference being that Solargraph type checking relies on YARD documentation instead of annotations.

hit8run · 7 years ago
Love the work you’re doing on Solargraph! Thx for it.
brigandish · 7 years ago
I wondered why no one had tried this instead. It's certainly a (much needed!) incentive to document methods.

I'm going to give Solargraph a look-see.

anonova · 7 years ago
> To enable static checking with srb, add this line (called a sigil) to the top of your Ruby file:

> # typed: true

Isn't this called a directive/pragma? A sigil is a symbol on a name.

Either way, I'm excited to see this finally out after seeing the past presentations on it.

ptarjan · 7 years ago
Thanks for pointing that out. It can be called all of those. We liked sigil from its connotation:

> Google defines sigil as, “an inscribed or painted symbol considered to have magical power,” and we like to think of types as pretty magical

https://sorbet.org/docs/static#fn1

dochtman · 7 years ago
That's a pretty unintuitive use, since "sigil" is more commonly used (in programming languages) as a single symbol, as in a non-alphanumeric character that's used as some kind of syntax.

https://en.wikipedia.org/wiki/Sigil_(computer_programming)

sdegutis · 7 years ago
I remember there was this CEO once who was new to the software industry and was looking for a word to describe non-small-business customers. When people suggested "Enterprise", he instantly dismissed it, and when they insisted this is already the word we all use to mean this, he actually opened the dictionary to prove that it wasn't quite accurate. What I took from this is that, when cultures or conventions already have momentum, sometimes you just have to go with it. This is the same reason I don't like Go.
weeksie · 7 years ago
Bummer. That kind of name overloading has the potential to be needlessly confusing down the line. "Sigils, I mean well, they're like pragmas but in Sorbet we call them sigils." [x a billion]

Now's the time to fix that stuff.

(In any case, I'm quite keen to start playing with sorbet, looks great!)

fouc · 7 years ago

  test/test_corpus.cc
  364:        auto checkPragma = [&](string ext) {
  368:                    << "Missing `# typed:` pragma. Sources with ." << ext << ".exp files must specify # typed:";
  377:            checkPragma("cfg");
A quick look at the source shows that it may have been called pragma at one point.

EDIT: I'm guessing "sigil" was chosen because it's closely matching the "signatures" or Sigil.sig method name?

e12e · 7 years ago
Ruby has perl-like sigils, eg: @i_am_instance_var, $i_am_global. Additionally, one might consider array literals sigil-like (like %w[a b c d e f g]).

https://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/vari...

cperciva · 7 years ago
The terms all overlap a bit, but I would interpret "directive" or "pragma" to indicate that it's conveying meaning to the Ruby interpreter. This is exactly the opposite -- it's a comment as far as the Ruby language is concerned while conveying meaning to an external tool.
FpUser · 7 years ago
I've never understood the so called advantages of dynamic typing. To me it looks like a land mine in one's project waiting to blow at run time. And what for? Do developers code so fast that the time spent on typing something like "int i" will provide any real savings? Now vendors are trying to patch those with bolted on top syntax extensions/derived languages that need to be transpiled. What a mess.
mberning · 7 years ago
Most people fixate on the terseness that it can afford in a language. I suppose I do like that but for me it is not a huge deal.

What I think is more important is the flexibility that it brings to express design patterns that in other languages, like Java for example, can become very cumbersome. I can’t tell you how many times I have been in the bowels of some Java code and found some method that takes a concrete implementation of something that could or should be an interface when I really want to pass in something different. Then you are like “let me extend and fix this class” and then you end up just extending and fixing 1/2 the code base to get done what needs to be done. In a language like Ruby I would just pass in an object that responds to all the needed methods and it would happily work. Ideally you wouldn't get into these type of messes in statically typed languages because people would follow good design principles all the time. But people are fallible and in reality messes are everywhere in statically typed languages.

So I think the approach of adding type enforcement if desired is a nice approach considering there is a large amount of code out there that probably doesn’t benefit much from it.

jeremycw · 7 years ago
When you're consuming JSON that has deep nesting, arrays that contain multiple types, etc. Something that may be two lines of code in a dynamic language could be as much as 100 lines in some static typed languages.
choward · 7 years ago
Sure, you could write one line of code to read it in as maps and arrays, but at some point you need to validate your input from the outside world to convert it you your domain objects. Using a dymically typed language doesn't magically make that problem go away.
FpUser · 7 years ago
Depending on library used it can actually be the same amount of lines. The lines are a bit longer of course.

Example

  auto obj = JSON(text);
  int age = obj.["persons"][3]["age"];

loxs · 7 years ago
That's probably the only real case, yes. And still, even this is a non-issue with things like io-ts https://github.com/gcanti/io-ts

This is my go to tool (and language) nowadays when I need to do something JSON heavy for a prototype.

Deleted Comment

SomeOldThrow · 7 years ago
It makes unit testing much easier. That’s the best explanation I’ve found. Rapid prototyping too, but that just means you’re backloading tech debt so that’s at best neutral in pure technical terms. In a startup context backloading tech debt is deeply desired.
mruts · 7 years ago
Type checking isn’t really related to typing “int.” Many languages infer types. In fact, Hindley Milner type systems should be able to infer all types without explicitly specifying any of them.
camjohnson26 · 7 years ago
Sometimes I do code that fast. When you’re messing around just trying to find out if something is possible you want to write as much code in as short a time as possible, and Python shines for that. Every second wasted typing is a second that could have been spent moving forward.

Of course the problem is that the prototypes are terrible to maintain and eventually need unit tests and typing. But you don’t want to waste time adding those things if you’re not even sure your idea will work. I use strongly typed languages in production and couldn’t imagine using Python for that.

kccqzy · 7 years ago
If typing speed is your main limitation, it means either you can improve your productivity dramatically by improving your typing skills, or your language is limiting you so much that you don't have good abstractions to enable you to think at a higher level.
loxs · 7 years ago
I don't see how typing F# is slower, longer or less convenient than typing Python (spoiler alert, it's not). And you also get things like actual lambdas, pattern matching, currying, real parallelism and more and more.

It's only that people believe there is no need to learn anything beyond Python because it's "easy", which it's not, once you go beyond several hundred lines of code. But the myth somehow continues to persist.

FpUser · 7 years ago
This logic transpiles(TM) to this in my brain: a) I am messing around and need to write 10 lines of code. Can I write it fast and without thinking? Sure and not needing to type int/float/whatever will save me couple of seconds. If I iterate and rewrite that short piece 10 times then I just saved 20 seconds. Chirp chirp ... . Do I need special language for just that? Lemme guess ... b) I am messing around and need to write few hundred or thousands lines of code. Can I write it fast? Maybe but it is likely that good chunk of time will be spent thinking. I doubt that at this point not declaring type will save anything worth noticing. But that of course is my opinion
hartator · 7 years ago
Awesome work.

    sig {params(person: Person).returns(Integer)}
    def name_length(person)
Not sure if I dig the syntax. Furthermore arguments seems to be the official names for method arguments, not parameters. eg, `ArgumentError`. `params` also feels like it's linked to Rails `params` variable in controllers. It can be confusing.

Something like this will also feel more Rubyist:

    def name_length person: Person, return: Integer
But it probably requires a deeper hack or a change in MRI.

ptarjan · 7 years ago
Thanks for the idea.

We used `params` because Method#parameters was what they called it in the standard library. I actually had it as `args` originally until someone pointed this out. https://ruby-doc.org/core-2.6.3/Method.html#method-i-paramet...

As for the syntax change, we are actually on our 8th iteration of the syntax. We really wanted this to NOT be a fork of Ruby so finding something compatible was very important. For example that's why it has the weird `sig {` syntax too, we didn't want to have to cause load-time and cyclic dependencies from adding type signatures.

hartator · 7 years ago
> We used `params` because Method#parameters was what they called it in the standard library

Super interesting. We should probably have being consistent for naming parameters vs. arguments in stdlib. It's too late though!

matharmin · 7 years ago
I'm not sure how consistent it is with everything in Ruby, but parameters is technically the correct term here. A parameter is a variable definition, while an argument is the value that is passed to the parameter.

ArgumentError is still consistent with this definition (it's an error with the value you passed, not with the definition). However, params in a Rails controller does violate this definition.

lloeki · 7 years ago
Different levels of abstraction/concerns. Params in Rails come from HTTP params i.e the conceptual merge between GET query strings and POST body (e.g forms, but also JSON).
kazinator · 7 years ago
In computer science, "formal parameters" is the name for those named variables that are established on entry into the function and immediately receive external values. "arguments" are the values that they receive. A function has only one set of parameters, but a new set of arguments in each invocation.
kentor · 7 years ago
My view is you define methods with parameters, you call methods with arguments.

`ArgumentError` is consistent with an error during call time.

ljm · 7 years ago
That might work in .rbi files because they could be parsed independently of Ruby itself (basically giving Ruby the C-style header+impl split).

As far as ruby goes, though, it would conflict with keyword arguments.

pbiggar · 7 years ago
Dont know if this applies, but my understanding is that in functions, a parameter is the name of a declaration which when called will receive an argument.

Deleted Comment

whycombagator · 7 years ago
Related, Square wrote a great article: "RubyKaigi and the Path to Ruby 3"[0]. The section titled "Static Analysis" high level compares Sorbet to Steep

[0] https://developer.squareup.com/blog/rubykaigi-and-the-path-t...

sickcodebruh · 7 years ago
It’s my understanding that the Sorbet team is involved with bringing types to Ruby 3. I’m unclear on whether it will be Sorbet itself or if it’s elements of it. Can’t dig up the source right now, maybe someone can corroborate this?
darkdimius · 7 years ago
This is true, we're part of a single working group that's working on types for Ruby3. https://twitter.com/darkdimius/status/1119130004313350144 has some detail
jtms · 7 years ago
Though I haven’t yet used it for anything in production, I think if I were starting something greenfield and wanted “Ruby with static types” I would go with Crystal. I really enjoy writing it and the performance you can get is quite a significant boost over Ruby.
sickcodebruh · 7 years ago
I’d still go Ruby. A language’s ecosystem and community are as much factors in why someone should choose or avoid it as its syntax. Both of those things are fantastic for Ruby — I’d argue that they’re some of its best features, in fact. Crystal? Not so much.
jtms · 7 years ago
I’m a long time veteran of Ruby and someone who deployed production Rails apps in EARLY v1. I absolutely love and adore it and it’s by far my favorite language to work with. That being said, when I can write in a very stunningly similar language and get 10 to 100x performance with very little extra effort I am going to strongly consider it when deciding on my stack. Also the ecosystem for crystal is not terrible at all. I think it’s a great project and shouldn’t be ignored because “the ecosystem”