Connecting...

W1siziisimnvbxbpbgvkx3rozw1lx2fzc2v0cy9zawduawz5lxrly2hub2xvz3kvanbnl2jhbm5lci1kzwzhdwx0lmpwzyjdxq

Types: Never commit too early by Stéphane Derosiaux

W1siziisijiwmtgvmdkvmtqvmdgvmzcvmduvntq2l2d1bw1pymfyy2hlbi1mcnvpdc1ndw1zlwjlyxitc3dlzxruzxnzltu0njmzicgxks5qcgvnil0swyjwiiwidgh1bwiilci5mdb4otawxhuwmdnlil1d

It's Friday and today we have another great article written by Stéphane Derosiaux on Types: Never commit too early, happy reading!

 

'Types: Never commit too early

A few days ago, I was answering to a tweet from @kubukoz (https://twitter.com/sderosiaux/status/1027653596404436993):

“Or F[_]: Sync. Never commit too early. >:-)”

This leads me to think a bit more about it later. When you think about something, why not write it down to share it?

 

Cross-post

This medium post is just an overview of the series of 3 articles I’ve written on my blog:

Types: Never commit too early

Consider reading it to get the full scope.

 

Typeclasses

At first, it was supposed to be something quite straightforward: I just wanted to demonstrate the power of the typeclasses, and the “genericity” (not to be confused with generics!) they offer: they are not tied to any specific implementation.

def prog[A, F[_]: Console: Async: DbAccess: Drawable](p: F[A]) = ???
  • Typeclasses just declare a “contract”, a “protocol”, a “capability” that some types (here F[_]) have to fulfill.
  • They provide ad-hoc polymorphism: a “has-a” relation instead of “is-a” that we find in OOP through inheritance.
  • They have their own constraints: they must be coherent. What if a type has 2 distinct implementations provided? Who wins?
  • They can replace a stack of Monad Transformers and lead to better performance, less code, easier maintenance.
  • The implementations can be very different: they can boost the application performance just by changing one line! Or they can crash it... (if not stack-safe for instance)
cats-effect and cats-mtl provides tons of typeclasses to deal with sync/async effects (Sync, Effect…) and Monad Transformers (MonadState, ApplicativeAsk…).
 

Connascence

It leads me to learn about Connascence of Types (other types of connascence are described). The connascence describes the relationship, the coupling, between callers and callees.

The connascence of name

The connascence of name deals with the function and arguments names.

To call a function, the caller must know the name of the function (!) and sometimes the argument names. If you change the name of the callee: all its callers must change too.

Same for the argument names, but it’s often not necessary: not all languages handle argument names when calling a function “f(id=11)”, they just handle the argument positions “f(11)”. But how to distinguish between if we didn’t swap arguments if our function is “f(bool, bool)” ?

The connascence of type

The connascence of type deals with the types of the arguments and the return type of a function.

If you change any of these types, the callers must be changed too. It’s only “valid” in statically-typed languages which compile the program. In JavaScript, your program will still be “valid”, but will crash at runtime.

There are other types of connascence: position (of arguments), algorithm (implementation details), etc.

Free Theorems

After the connascence, I had to talk about the Free theorems.

They are the idea of Philip Walder: it‘s everything you can say about a function, just by looking at its signature.

def something[A](a: A): A

Guess: what does this function can do? (hint: not only what you think)

A nice and well-known talk from him is Propositions as Types, where he describes the power of induction thanks to types.

It’s strongly linked to polymorphism and the Functional Programming principles. Functions must be:

  • Total: no partial functions
  • Deterministic: given a fixed input, the output should be the same
  • Side-effects free: no mutation outside the function scope (like println)

Without those rules, types can lie. Imagine you return null or throw an exception: does it appear in the return type? No! (don’t talk about throws in Java). In Scala, we never use null: we use Option[A] to declare it’s nullable.

 

Types: Never commit too early

I hope this small overview will tickle you. My series talks about that and much more. You could probably learn something from it, don’t hesitate to check it out.' 

 

This article was written by Stéphane Derosiaux and posted originally on Medium