
RDL: a lightweight system for adding contracts to Ruby - muhic
https://github.com/plum-umd/rdl
======
phpnode
It's always baffled me why more people don't seem interested in adopting
design by contract, it is a ridiculously powerful tool for writing quality
software.

Here's a Babel plugin which adds design by contract to JavaScript, squeezing
it into existing JS syntax (the result is really similar to Eiffel) -
[https://github.com/codemix/babel-plugin-
contracts](https://github.com/codemix/babel-plugin-contracts)

and here's what it looks like in a reasonably complicated program -
[https://github.com/codemix/malloc/blob/master/src/index.js](https://github.com/codemix/malloc/blob/master/src/index.js)

(disclosure: I wrote this)

~~~
spriggan3
> It's always baffled me why more people don't seem interested in adopting
> design by contract

Because it's yet another layer on top of other layers, because it has
performance implications ... A few languages such as Vala support some form of
contracts, this kind of feature is more useful when part of the language
itself, not some third party babel plugin that leads to codebase fragmentation
as one just had yet another layer to the compilation pipeline. No offense,
that's a nice thing you wrote, I'm just not going to use this kind of thing
and add more complexity for very little gain. To me tests ARE the contracts.

I would only be willing to pay the cost of transpilation with something like
Typescript which adds a signification value. Babel and co ? not worthwhile.

~~~
phpnode
Your argument seems more like one against transpilers in general.

Contracts are useful during development, they're typically stripped out in
production builds, so there's no performance overhead there. If you find a bug
in production, turn on your contracts and you'll quickly discover the source
of the error. Contracts can validate the state of the world at runtime in a
way that can never be covered by unit tests, unless your tests cover all
possible inputs to your program. It doesn't mean you don't need unit tests
too, they are yet another layer of safety.

I use this in combination with Flow, which means I have to transpile
regardless, so the overhead is very low for me. Of course I'd like them to be
part of the language proper, but for that to happen there needs to be
developer demand first.

~~~
pkroll
If it's stripped out during production, that sounds more like an assert than a
contract. What's the line over which you'd call an assert a contract...?

~~~
phpnode
Contracts are just structured assertions, they're very similar.

------
echelon
Typing is such an important and powerful construct. It'd be amazing if
scripting languages like Ruby and Python built optional typing into future
versions, especially if they could be used in speeding up the execution time.
If nothing else, type safety for function signatures would be a huge win for
productivity, testing, and would cut down on a large class of programmer-
introduced bugs.

~~~
pmontra
I used languages with static types for half of my professional life, the last
one was Java, and languages with dynamic types in the other half. I never felt
like I have more bugs in dynamic typed languages. What I felt is that I don't
have to waste time writing stuff like ArrayList<Whatever> when just something
= {} works perfectly well in practice.

I understand that many people say that with static typing if it compiles it
works, but I remember using debuggers quite a lot.

I'd say that if one wants types there are plenty of languages to choose from.
There is Crystal if one likes Ruby.

Contracts are interesting. I remember Eiffel and other languages. Those could
be useful regardless of the kind of typing the language use.

BTW, invariants are another useful tool when designing some algorithms and
were neglected recently.

~~~
bjz_
> I never felt like I have more bugs in dynamic typed languages. What I felt
> is that I don't have to waste time writing stuff like ArrayList<Whatever>
> when just something = {} works perfectly well in practice.

Java is a pretty terrible language when it comes to static types. If you have
a language that allows you to work with types in a succinct and expressive
way, you end up with a powerful modelling tool that can help you reason about
and design programs. The side-effect of this is to have far less runtime
crashes (you know what cases to check for, like nullable data), great
documentation for your future self and your fellow devs, and a greater liberty
to do large scale refactors without worrying about breaking things.

~~~
twblalock
The self-documenting nature of statically typed programs is something that
critics often miss. Making a contribution to an existing codebase is far
easier when it is statically typed. You can very easily understand what you
ought to do, because the constraints of the type system help you figure out
exactly what things are, what arguments you can pass to a method, how the
other programmers used the types, etc.

In contrast, contributing to an existing codebase in PHP or Rails is much
harder. Nothing will stop you from sending the wrong arguments to a method, or
adding members to classes that should not be modified, or even simply
refactoring and forgetting to change all of the usages of the types and
methods you modified.

~~~
Retra
Well, the converse argument is that most dynamically typed languages allow you
to explore the codebase in a REPL by playing with it. And there's a reasonable
amount of noise that is added by static types, since often the types don't
tell you how to use them, so you have to read the docs anyhow.

Which really means there's a big difference between static types that everyone
knows and uses, and those that someone invented for particular use. That
difference seems more significant than the static/dynamic divide.

~~~
twblalock
There are statically-typed languages with REPLs, e.g. Scala, C#, F#, and the
upcoming Java 9, so REPLs are not an advantage of dynamic languages. There are
even REPLs for C++.

Many people's impressions of static languages are based on Java from 10 years
ago. It's really quite different now.

------
chrisseaton
RDL supports most of the serious research anyone is doing into types in Ruby.
See the papers with Foster as an author under Types here
[http://rubybib.org](http://rubybib.org). I hope the Ruby core team is
watching their progress since some kind of typing is being debated by Matz.

~~~
ksec
That is "the" problem, "how" do we know if the Core Team are watching /
discussing / debating. Comparing a similar situation to the Python circle (
You can laugh about Python 3 all you want, but that is another issue ), which
is clearly layout and in some way beautifully presented.

------
Dangeranger
After changing focus from Ruby to functional languages recently I've found
that optional types can be really helpful in a lot of situations.

Ruby also has another popular and mature library that I am surprised nobody
has mentioned yet named 'Contracts.ruby'

[https://github.com/egonSchiele/contracts.ruby](https://github.com/egonSchiele/contracts.ruby)

This syntax is also more appealing to my eyes than what rdl provides.

    
    
      Contract Num => Num
      def double(x)
         x * 2
      end

------
smizell
Very cool. I experimented with something similar in JavaScript.

[https://github.com/smizell/snug](https://github.com/smizell/snug)

For me, it is useful for runtime checking data that may come across the web.

------
woodruffw
Good to see PLUM (Programming Languages at the University of Maryland)
releasing their work on GitHub. They're among the most talented in the
department at UMD.

~~~
socrates1024
Totally. PLUM is a great team, and this work on ruby contracts from Brianna
and Jeff is particularly awesome. By the way, their newest paper about the
work in this github is going to be at PLDI:
[https://www.cs.umd.edu/~jfoster/papers/pldi16.pdf](https://www.cs.umd.edu/~jfoster/papers/pldi16.pdf)

(disclaimer: I just graduated from PLUM)

~~~
woodruffw
Awesome, thanks for sharing! And congratulations on graduating.

I'm an undergraduate, so my experience with PLUM is just that of an admirer
looking in ;)

------
metafex
Oh wow, even with support for static type-checking. It really makes me want to
give ruby another shot.

Piggybacking on this: apart from F*, does someone know of a language or
support for existing ones for contracts, loop-invariants and possibly
verification?

Dafny and Spec# aren't very general-purpose and apart from those nothing much
comes to my mind.

~~~
david-given
Ada has robust preconditions and postconditions.

Untested code follows:

    
    
        procedure swap(a: in out integer, b: in out integer)
        with
          pre => a <> b -- just for example purposes
          post => (a == b'old) and (b == a'old)
        is declare
          t: integer;
        begin
          t := a;
          a := b;
          b := t;
        end
    

(Sorry, couldn't think of a sensible small example which uses both pre and
post, hence the terrible precondition.)

Note that the postcondition can refer to the old values of the variables with
the 'old suffix --- the values will be automatically saved on entry to the
function and used for comparison later.

Unfortunately the pre- and postconditions have to be specified in the public
part of the module, so can't see any private module variables, which forces
you to jump through hoops if you don't want to expose your module's internal
state (e.g. checking to make sure that functions on a state machine are called
in the right order).

You also get type invariants, where you can specify an expression which must
always be true for a number:

    
    
        subtype Even is integer
        with dynamic_predicate => (Even mod 2) == 0;
    

Or, if you really want your mind blown:

    
    
        subtype Even is integer
        with dynamic_predicate => (for some N in integer => (Even == N*2));
    

There's also a static_predicate form which only supports a restricted
predicate expression but which can be checked at compile time.

~~~
metafex
Thank you for the example.

Also: SPARK is another one I forgot. I guess I'll have to think of a nice
example and just implement it in a Ada, F* and with RDL to get a hang of the
differences and features.

------
dkarapetyan
This is fantastic. They even have type checking. Looking forward to the day
this turns into something like tsc.

------
programminggeek
Don't get too excited. It's not rails enough for the ruby community to ever
seriously use it. I know this from firsthand experience going down the same
rabbit hole a few years ago.

~~~
ksec
>rails enough

Cant upvote you enough. I am getting the sense that DHH dictates more of Ruby
rather then Matz. ( Which isn't necessarily a good or bad thing )

------
bjz_
Anyone know what the performance implications for using this would be?

------
arunix
Some differences from Eiffel contracts: no class invariants, and
postconditions don't have access to previous object state.

------
nurettin
I wonder if contracts can be used to speed up the execution instead of slowing
it down.

