
Reasoning with Types in Rust - miqkt
https://aaronweiss.us/posts/2018-02-26-reasoning-with-types-in-rust.html
======
bringtheaction
> A function of type fn<T>(T) -> T must:

> return its argument or

> panic or abort or

> never return

This confused me for a moment because I thought “why? it only says the return
value must be the same type as the argument, not that it must have the same
value”, but of course since the type can be anything there is no operation
that is guaranteed to work that you can perform on the argument value. You
can’t for example multiply by two because not all types will support
multiplication by an integer.

~~~
hhmc
Perhaps this is subverting the type-theoretic (in a CS sense) point being
made, but in C++ you could quite reasonably write a function:

    
    
      template<typename T>
      T fn(T t){
          return t * 2;
      }
    
      fn(4.2); //fine
      fn("foo"); //fails
    

because the inability to multiply by 2 isn't a problem until an incompatible
type parameter is instantiated. Is this not the case in rust?

~~~
beojan
That's because templates have no type-checking in C++.

Ideally, you wouldn't be able to do this with concepts, but I don't know
whether that's true for the concepts that finally made it into the standard
(i.e. I don't know if it would be an error to call a function or operator on
an argument if that function isn't required in the concept specification.).

~~~
seanmcdirmid
C++ templates have type checking after expansion, the type checking just isn’t
modular.

------
bluejekyll
I loved this post. It’s very readable and introduces some interesting concepts
related to type safety and some potentially simple use case in the context of
access to private data, guaranteed from a type pattern.

As was pointed out in the Reddit conversation about this [1], the
parametricity (new word I learned while reading this last night), will be lost
with specialization.

Personally I want specialization for all the joy it will bring, and I don’t
see this as a huge loss, but I wonder what other people’s thoughts are on
this?

[1]
[https://www.reddit.com/r/rust/comments/80eis2/reasoning_with...](https://www.reddit.com/r/rust/comments/80eis2/reasoning_with_types_in_rust/?st=JE7ZUBNM&sh=5df7aace)

~~~
matt-noonan
To me, parametric polymorphism is much nicer for reasoning about a program
locally / modularly. It's kind of like reasoning about a function with linear
control flow vs reasoning about a function with lots of nested if/elses. You
can do the reasoning once and be done with it.

I tried to make a general point along those lines in this blog post, thought I
think it deserves more extensive examples. [http://storm-
country.com/blog/abstract-is-simple](http://storm-country.com/blog/abstract-
is-simple)

------
skybrian
The _Secret_ example is basically just encapsulation. It reminds me of the
HTML type used in Go's standard library to avoid XSS vulnerabilities in HTML
templates due to lack of escaping. [1] Any string that's not cast using HTML()
is considered unsafe and will automatically be escaped.

In practice, this is used to make security audits easier. It's not that you
can't defeat the system, but security review only needs to look at all the
places a string is cast to or from the HTML type and verify that they're in
fact safe. This is considerably easier than it would be with bare strings,
though better encapsulation would help. (In Go, this could be done with a
struct that has a private field, but that's not what they did for some
reason.)

This is an old trick, also used by GWT [2] and other languages. Language
support for zero-overhead, encapsulated wrapper types makes this particularly
convenient; otherwise you have to decide if the performance cost is worth it
for a widely-used type.

[1]
[https://golang.org/pkg/html/template/#HTML](https://golang.org/pkg/html/template/#HTML)
[2]
[http://www.gwtproject.org/javadoc/latest/com/google/gwt/safe...](http://www.gwtproject.org/javadoc/latest/com/google/gwt/safehtml/shared/SafeHtml.html)

~~~
jerf
You can write parametrically polymorphic code in pretty much any language that
has a concept of polymorphism [1]. It's not difficult to avoid doing the
things that violate it. The problem arises in that if your language doesn't
guarantee it, you don't know what third-party code will do. Go by no means
guarantees parametric polymorphism, for instance, and technically a wizard
armed with "reflect" can do anything they want, but in practice you can get a
lot of mileage out of it even if it isn't guaranteed.

I write a lot of networking code and one of the patterns I use a _lot_ is to
get a socket from something (connecting, accepting, whatever), do any socket-
specific configuration I may need to do on the socket immediately, and then
pass it to a function to do the real work that takes an io.Reader or io.Writer
or whatever minimal interface it is I actually need. This has two major
benefits: First, it makes it clear that the "real" code is only going to do
certain things, and second, it makes the "real" code much easier to test
because it's tedious and difficult to mock a real socket, but quite easy to
pass something an io.Reader and ensure it does the right thing.

It's certainly not a new trick and it can be applied in a lot of existing
languages, but as programming ideas go, it's still a relatively new concept to
the programming gestalt community [2]. I expect to see this idea coming up
more and more over the next 20 years; I wouldn't be surprised that on the
cutting edge programming language side, it becomes as expected to have some
form of enforced parametricity in your new shiny language as it is to have
closures.

[1]: For the purposes of this discussion, dynamic languages have only one
type, "Variant", and thus don't really qualify as polymorphic in this manner,
despite their apparent extreme polymorphism.

[2]: Yes, it's a couple of decades old, but measured in person-years of
understanding it is minuscule compared to the community as a whole.

~~~
skybrian
I said it was basically the same thing, but a big difference is that we aren't
using polymorphism, just encapsulation.

You don't need reflection to break parametricity. All you need is instanceof
(in Java) or a type switch (in Go), and this is very common style since sum
types don't exist and that's how we pattern-match. (Along with the visitor
pattern.)

Parametricity seems to be when a language doesn't have these things; if you
want to pattern-match on types, there needs to be a sum type or an operation
that returns one.

It's not clear that programmers used to an object-oriented style will go along
with the idea that downcasts are bad and should be forbidden. Is it worth
removing a useful escape hatch (particularly in framework-heavy code) to gain
an esoteric form of type-based reasoning?

But if you try Rust, you're fighting the borrow checker anyway, so perhaps
this additional inflexibility isn't that noticable?

~~~
jerf
"You don't need reflection to break parametricity."

Correct; I cited reflect just because it lets you do _anything_ ; i.e., you
can get a type you don't understand at all, and reflect can go groveling
through the type to see if it can find an embedded type it does understand, or
even directly muck about with unrelated struct values, or any other crazy
thing. Type switching requires you to be able to name the types you're going
to examine in advance; with reflect you can even do horrible things to types
that didn't exist when you wrote the code.

But then, the answer is mostly not to do that. Go isn't academically pure, but
neither is it full of people writing crazy code like that. And so,
_technically_ , you can't use this reasoning in Go... but even so, enough of
it is there that I get some mileage out of it. I find my expertise in Haskell
transfers in Go in some bizarre and unexpected ways, because while Go doesn't
have much, Haskell taught me a lot about exploiting what is there to the
maximum I can. Even though by Haskell standards _haughty sniff_ Go is barely
even a _programming language_ (well I never!).

------
drchickensalad
Site isn't very usable on mobile.

~~~
aaronweiss74
Does your mobile browser support CSS Grid? If it does and there's still an
issue, I'd love to fix it.

~~~
shakna
Grid doesn't have great support on mobile yet.

I'm sure you want to stick with it, and aren't really interested in something
else, but Grid only started getting solid support across all the main mobile
browsers in January. Lots of mobile devices are stuck on older versions,
because of vendors not releasing updates.

~~~
aaronweiss74
It's been supported on iOS for just about a full year now according to
caniuse. Unfortunately, they seem to lack meaningful historical info about
Android, but assuming some kind of feature parity between Chrome versions on
mobile and desktop, should've been about the same time.

I will definitely stick with grid, but it does suck that people have mobile
devices that still haven't gotten these updates after a year. :\

------
rs86
Excellent fucking article.

