Skip to content

Instantly share code, notes, and snippets.

@rranelli
Created March 2, 2015 23:42
Show Gist options
  • Save rranelli/a1482979e0f984d74cc4 to your computer and use it in GitHub Desktop.
Save rranelli/a1482979e0f984d74cc4 to your computer and use it in GitHub Desktop.
braindump-7langs-7weeks

Talk

Why is it important to learn new languages ?

<Image of the pragmatic programmer book>. You should learn a new language every year because they bend your mind and teach you new ways too solve old problems.

Also, the fact of the language being new is not actually all that important. What is important is that the language has another paradigm and another way o seeing the world.

Disclaimer: All the languages we are going to talk about are turing complete. There is not actually something that you can do in a language but can’t in the other. But the thing is, some of them make it so damn harder than the others. Your problem domain is what will drive your choice of language.

How have I got to know the book. How many languages I worked with and ask people about it.

Emphasize also that the talk will by no mean be an exhaustive list of the features of the languages. A whole book is still not enough for a single language. A medium sized book for seven doesn’t even scratch the surface and a 45 minute talk even less so.

Most of the things that I will talk here the book is not deep, but if you never heard of the concepts, the book will give you the necessary jumpstart for a more deeper study.

The main reason of the talk is to instigate people to get out and read the book. Follow the exercises and learn a little bit about the language and why the whole thing is nice.

Small introduction about each language, telling name and paradigm.

Also, tell what is the movie character of each language.

Ruby: pure object oriented, class based, strict, strongly typed, dynamically typed. Astonishing metaprogramming capabilities. Mary poppins, brings joy back to programming.

Io: object oriented, prototype based, not-so-strict, strongly typed, dynamically typed (?). Character is ferris bueller.

Prolog: logic programming. Weird, so weird.

Erlang: Functional programming, non-pure, share-nothing, dynamically typed, and just as weird as prolog. Agent smith, a lot of power but no soul. Favors immutability, but let you ignore this if you want to.

Clojure: Lisp on the JVM with modern data-structures. Object oriented, functional, dynamically typed class based but that’s not actually important, astonishing concurrency libraries, extremely consistent syntax. Favors immutability, but let you ignore this if you want to.

Scala: Object oriented, class based, functional, offers control over strictness, statically typed, strongly typed, offers implicit conversions. Has traits, which are close to ruby mixins and something like type classes. Edward scissor-hands. Has a lot of power, but its awkward to use because people around don’t understand you the way they should.

Haskell: Functionally pure, non strict, strongly typed, astonishing type system with lots of inference. Metaprogramming with type classes and Monads. Makes some hard things easy and some easy things hard. The fact that Haskell is a pure functional languages allows the compiler to make heavy optimizations. Substitution principle.

Show a little excerpt of each language with it’s sweetest feature (also, explain the things you will talk later)

Ruby

Open classes and everything toplevel being accessible.

class Numeric
  def inches
    self
  end

  def feet
    self * 12.inches
  end

  def back
    self * -1
  end

  def forward
    self
  end
end

With this, you can write:

puts (3.feet.back + 8.inches.forward)

Also, the loved and hated method missing. Won’t even show an example of it.

With great powers come great responsibility too:

class Numeric
  def +(other)
    other - self
  end
end
Io

In Io, everything is an object. An object has ‘slots’ (attributes in the Js world).

The whole syntax is:

prototype message(args) repeat(args)...

You get new objects by cloning old ones. When an object does not know how to respond to a message, it forwards it to it’s prototype.

You get a crazy amount of reflection and introspection, see:

if(str == Nil,
   call sender someValue := "")

With this, you can emulate dynamic scope for all it’s glory and gore.

The whole async programming is built in to the message passing style:

futureResult := URL with("http://google.com/") @fetch
Prolog

Prolog is good for asking questions:

# setup relations between symbols
different(red, green). different(red, blue).
different(green, red). different(green, blue).
different(blue, red). different(blue, green).


coloring(Alabama, Mississippi, Georgia, Tennessee, Florida) :-
  different(Mississippi, Tennessee),
  different(Mississippi, Alabama),
  different(Alabama, Tennessee),
  different(Alabama, Mississippi),
  different(Alabama, Georgia),
  different(Alabama, Florida),
  different(Georgia, Florida),
  different(Georgia, Tennessee).

and then you can ask questions to it, and prolog will answer yes or no:

Alabama = blue
Florida = green
Georgia = red
Mississippi = red
Tennessee = green ?

# => yes

Prolog is declarative.

Scala

Scala piggybacks the JVM for a successful deployment platform and is also able to leverage seamlessly with existing java libraries.

Scala has type inference and generic types. Variables are immutable by default and you can even declare a parameter in a function to be non-strict (i.e. not evaluated prior to calling the function)

Scala has type classes and traits

class Person(val name:String)

trait Nice {
  def greet() = println("Howdily doodily." )
}

I have learned that TYPES and CLASSES are completely different things. <show the picture with the type hierarchy>

Actors built in

import scala.actors._
import scala.actors.Actor._

case object Poke
case object Feed

class Kid() extends Actor {
  def act() {
    loop {
      react {
        case Poke => {
          println("Ow..." )
          println("Quit it..." )
        }
          case Feed => {
            println("Gurgle..." )
            println("Burp..." )
          }
        }
     }
  }
}

// Syntax for message sending is the same as erlang's
val bart = new Kid().start
val lisa = new Kid().start

println("Ready to poke and feed..." )

bart ! Poke // <- This is async !
lisa ! Poke
bart ! Feed
lisa ! Feed

# => Ow...
# => Quit it...
# => Ow...
# => Quit it...
# => Gurgle...
# => Burp...
# => Gurgle...
# => Burp...
Erlang

Erlang is a product of years of research from Ericsson to develop near-real-time fault-tolerant distributed applications.

Erlang has no threading model. Erlang has instead lightweight ‘processes’ that share no data.

Erlang powers rabbitMQ, couchDB, Ryak and Whatsapp.

Erlang does not have traditional error checking and makes it really easy to monitor processes. If a process dies, you’re guaranteed to be notified.

Erlang has atoms, that are just like ruby symbols (they evaluate to themselves)

List = [1, 2, "three"]. # => [1, 2, "three"]

red. # => red

Pill = blue. # => blue

Pill. # => blue

Erlang pattern matches over values and not over constructors/types/tags So you end up using lists and records with atoms being used as ‘tags’

Person = {person, {name, "Agent Smith"}, {profession, "Killing programs"}}.

{person, {name, Name}, {profession, Profession}} = Person.

# => {person,{name,"Agent Smith"},
        {profession,"Killing programs"}}

Name.

# => "Agent Smith"

Profession.

# => "Killing programs"

You can not only match over atoms:

Animal = "dog".

case Animal of
  "dog" -> underdog;
  "cat" -> thundercat
end.

# => underdog

Process monitoring: gunloop monitor

Clojure

After Fortran, lisp is the oldest commercially active programming language.

Clojure is Lisp reborn, updated for a concurrent world. The whole syntax is:

(function-or-macro arguments ...)

CODE IS DATA. The eval-apply loop.

Clojure offers programmers with modern data structures as vectors, maps, sets, and so on. Although most of the power of lisp comes from its extremely consistent programing style, everything being lists and every operation being a function call, clojure abstracts away the details of the different ways of handling sequences in a common api: The sequence api. You can actually use lists, vectors, maps and such the same way you would lists, and the whole filter-map-reduce apis are the same.

There is a saying that Lisp gives you amazing functional and procedural powers just to leave you starving when needing data structures. And we know that smart data and dumb code works better than the other way around according to Eric S. Raymond. Clojure being on the JVM has the most chance of all Lisps to overcome this limitation.

Although Clojure is strict, the macro expansion allows you to simulate lazyness in a neat way. With this, the whole sequence api is actually lazy-ly evaluated.

Concurrency api is amazing, and offers you three ways to deal with mutable state: Agents, Atoms and Transactional Memory.

Clojure has multimethods which are a thing of their own. You can actually dispatch over the types of an arbitrary number of arguments. Clojure also lets you have thread-state.

The lisp paradox: Multimethods allow multiparadigm code. Macros let you define the language itself on the fly and control what is and what is not evaluated. The flexibility is an incredible strength.

macros and infix

(Actually, this whole internal reprogramability of Lisp heavily influenced Ruby)

Lisp’s extreme flexibility is also a liability. Being able to define your language on the fly tends to gravitate towards the state where each programmer has its own language and his programs have its own idiosyncrasies. Of course, it is possible to work around this situation with proper development processes.

Haskell

Although Haskell is statically typed, Haskell is extremely expressive. Uses a LOT of concepts from category theory. Its undoubtedly the most mind-bending and demanding language of the book. Also, the most enriching to work with.

module Main where

  factorial :: Integer -> Integer
  factorial 0 = 1
  factorial x = x * factorial (x - 1)

Haskell cuts you NO SLACK. Haskell is a PURE functional language, with no mutable state, lazy evaluation and probably one of the most powerful type systems out there. Great list comprehensions.

All Haskell functions take EXACTLY one argument. Partial application and currying:

prod :: Num a => a -> a -> a
let prod x y = x * y
let prod = \x -> \y -> x * y

let double = prod 2
let triple = prod 3

let double = (*2)
let plusTwo = (+2)

Haskell makes it so damn easy to express algebras and other more mathematical constructs.

Check my scheme parser: ~/code/rr-write-yourself-a-scheme/SchemeParser.hs

Explain the state Monad and how it is possible to work around mutable state.

What does it actually take to learn a programming language ?

(reference to Larry Wall’s big think video)

The basic
  • Its paradigm & primitives
  • Syntax
  • Type system (strong or weak, dynamic or static)
  • Evaluation rules (precedence, strictness and so on)
  • Idioms (how people organize and write code)
  • Libraries (what are the tools to get some real work done)
Little bit more advanced
  • Concurrency models
  • Metaprogramming and extensibility

Here I should surely talk about how the metaprogramming can make the program pretty hard to understand and reason about. Talk also about how higher order functions can allow one to be more expressive while not fucking the whole toplevel.

  • How to compose and organize large programs.

Show how languages compare in features

Object oriented paradigm:

Ruby and Scala are class based. Much of the polymorphism of Scala comes from generic types, and ruby has total no need for them. Show how IO bends the rules and gives strong emphasis on the most fundamental aspects of object orientation: (reference to Alan Kay paper)

Explain that you can actually model classes as objects if you give the objects of prototype class the method ‘new’ that actually clones itself into a new object. (god, this is crazy.)

Functional purity:

Talk about how some things can be so goddamn hard in Haskell and others can be such a bliss. Error handling and IO are good examples of how Haskell can fuck but save your life at the same time. Algebras are design patterns.

Show how this is actually not a big deal and that you can simulate mutable state in Haskell if you want to. Show your Scheme interpreter, IO Ref and shit. Also, show how one would implement this passing around a list of state with the state Monad.

Talk about how Haskell’s explicit mutable state allows it to leverage many optimizations for concurrency and parallelism while not brutally enforcing isolation in the Erlang way.

Metaprogramming and extensibility:

Talk about how ruby exposes the whole toplevel for everyone to poke. Contrast it with the Lispy way of writing macros to abstract control flow and other higher level things. Talk about how Erlang makes metaprogramming hard and that this is the reason why Elixir even exists. Although ruby is extremely dangerous, it is also extremely powerful. Show the picture of some chisel.

Talk about how the natural composition of behavior between objects lends itself to easy organization of the program as a whole and how this is lacking in the functional world.

How each language achieves Polymorphism

Mainstream object orientation (java and c#) achieves this with subtype polymorphism and inheritance.

Io is not as versed in the data polymorphism, but allows you to create your own operators and to use reflection on almost everything leading to potentially different constructs.

Ruby has a richer model with ‘classes as objects’, modules and mixins. Departs from the classic approach mainly because of the power and simplicity of the type system, where everything is an object.

Scala adds type classes (which are actually not covered in the book) and traits to the mix, allowing you to reuse pieces of implementation across classes. Of course, it makes heavy use of generics.

Haskell achieves polymorphism with type classes, type parameters (think java, c#, scala’s generics) and higher order functions. The composition patterns are much different.

Clojure also makes heavy use of higher order functions of course. Also, since lisp functions actually take more than one argument, clojure uses the common lisp multiple dispatch, in the form of the so-called multi-methods, to dispatch a function over an arbitrary number of types. <Show an example of multiple dispatch>

Erlang has the standard higher order functions thing, but is not actually powerful in the metaprogramming / polymorphism front. This tends to make the development of libraries and frameworks not as easy as in the other languages. That is the main reason for the existence of Elixir (also, to clean up the weird syntax).

Also, pattern matching plays a big role here.

Concurrency models

The current mainstream OO implementation issues with global shared state (the heap) is not a good fit for the concurrent world we live in. This is a main thing in the book. All the languages in the book show different approaches.

IO is single threaded but has nice concurrency libraries. Talk about how it relates to Javascript and Lua a lot. Ruby has threads and fibers <(? which are coroutines ??>.

Actors in Io, Scala and Erlang. STM in Haskell and Clojure.

Concurrency in ruby with… threads.

Controlling mutable state

Classify languages in how much fear you have for ‘effect at distance’. Say that ruby allows one to move anything from virtually everywhere (with the exception of Refinements!). Talk about how some of the intrinsic data isolation in some languages lends itself nicely to actor based programming.

Pattern matching

Talk about pattern matching to some extent. Explain what is destructuring and how different languages take different approaches. Talk about symbols in lisp and ruby and atoms in erlang.

Constraint logic programming

Emphasize the whole ‘your domain shapes your language’ with prolog. Prolog is made to solve problems like sudoku and eight queens. But is not actually fit for much else.

Drafts and ideas

Seven languages in seven weeks talk

=> Seven languages: Ruby, IO, Prolog, Scala, Clojure, Erlang, Haskell.

All languages have first class functions, so you can do most of the things in about the same level of verbosity.

Different paradigms and different ways to express it.

Object orientation: Class based, prototype based, mixed with functional stuff.

Functional: Different ways to think, totally different.

Prolog: for totally different applications. You can solve Sudoku with just the problem description.

Erlang: For highly available applications, complete and utter isolation of data. Share nothing. Erlang has a lot of power but no soul. Extremely reliable and scalable to the core. Whenever an Erlang process dies, you are guaranteed to receive a notification of this. Erlang powers ryak, couchdb and rabbitMQ. It’s not pure.

Haskell: Pure functional programming. Many many ways to deal with mutable state and concurrency. You must tag every mutable value or function with an specific tag: No surprises. Complete application of the substitution principle. Lazy, not strict. Haskell was created and built in a committee. Haskell relies HEAVILY in Monads and can express algebras in a very natural way. Haskell has the most powerful type system ever. You don’t even has to declare types. A MUCH MORE POWERFUL polymorphism mechanisms

-> Alergic to static typing. Boy, you’re alergic to BAD static typing.

-> Show the many many ways you can write a factorial function in Haskell. -> Purity brings you the full power of substitution principle, memoization -> and so on, so that you can be powerful and stuff.

=> What it actually takes to learn a programming language ?

Syntax, Type system, Evaluation rules, Idioms, Libraries.

Erlang was born from Prolog and Fortran. The first interpreter for Erlang was written in Prolog.

=> Concurrency models.

-> Every programming language gives you ways to do the following:

=> Syntax

=> Scala is edward scissor hands => A horrible and amazing hybrid of pure OO and pure FP. Much influenced by Haskell.

Scala and clojure piggyback on the JVM, and that ends influencing the design of the language.

Scala will feel much restrictive to people from the FP side, but gives a much needed freedom to the java people.

=> Talk about testing.

Encapsulate implementation. Polymorphic data: vary details of implementation by allowing different control flows (partial application in fp and collaboration in oo). Composition of behavior. Types. Encapsulate data and behavior

=> IO gives strong emphasis on message passing. It does not hide you The whole syntax is: prototype …message(arg)

You can define your operators and your own syntax extremely easing.

if(str == Nil, call sender someValue := "" doSomething )

IO has a great concurrency library: Actors, messages, coroutines, immutability. The very simple syntax lends itself nicely to metaprogramming.

Has small footprint, is embedable, metaprogrammable and shit.

=> Clojure: Lisp on the JVM (!) Extremely consistent with syntax. Actually, almost no syntax. Metaprogramming is easy because everything is so damn consistent.

Not so Lispy, no tail call recursion (it’s the jvm’s fault!). Clojure adds modern data structures, and a little bit less parenthesis. Puts restrictions on macros and reader macros.

AMAAAAAZING concurrency model. Actions, transactional memory and stuff.

(print "Do or do not. There is no try.")

Lisp was in exile for years, just like YODA. In the end you get to understand that the language is so amazingly powerful that all you understand about programing is subverted to an extreme simple and clever way.

=> Ruby: It’s all about the magic and happiness. Ruby has a SHIIIIIIIT-load of syntatic sugar. Ruby has MANY right ways to do stuff, the way it’s most fun to the program.

Extremely open, just like lisp. Sometimes there’s not enough discipline. Terrible support for concurrency from the beginning.

=> Concurrency

The whole object oriented paradigm with global shared state is NOT the right fit for multi-core processors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment