Skip to content
David Jeske edited this page Oct 5, 2021 · 37 revisions

One way to understand a language is to compare it to its contemporaries. Since Google Go and Irken both support Structural Typing, and that is a fairly rare feature among languages, it's a good comparison to make to understand something about Irken.

Before we get into the details, two of the biggest differences between the languages, and which we'd like to call out first, are..

  • Go is mature, while Irken still in it's infancy with few programs written in it
  • Go has extensive libraries and documentation, while Irken is sparsely documented with few libraries

In other words, Irken is very much still a research project, while Google Go has lots of 'real things' written in it. With that disclaimer aside...

Similarities

Both languages:

  • Are Strong Static Typed, with Structural Typing
  • Compile to (relatively fast) native code
  • Use Tracing Garbage Collectors (Irken's is very simple, Go's has impressively low pause times)
  • Have non-overloaded function/method dispatch
  • Have extremely lightweight co-routines (go-routines)
  • have lightweight stacks (sometimes called Stackless)
  • are functional imperative hybrids

Differences

  • Irken is a Scheme like s-expression language, while Go is a C-like syntax

  • Irken supports global Type Inference, allowing you to omit nearly all types, while Google Go only supports local type inference of assignment statements

  • Irken supports compile time macros, while Go does not

  • Irken has parametric typing, allowing the creation of generic data structures such as (list 'a), and generic functions such as (map fn lst) : (('a -> 'b) (list 'a) -> (list 'b)), while Google Go has no Generics, only the parametric built in types Array, Slice, and Map

  • Irken uses Row Polymorphism, so operations on Structural Types do not lose their full type, while Google Go uses Structural Subtyping, so operations on Structural Types are coerced to the reduced type

  • Irken has first class continuations, while Go does not

  • Irken has Exceptions, while Go does not - though we use them sparingly

  • Irken does not allow null pointers, while Go allows any variable to be NULL

  • Go has a structured concurrency pattern called Channels, while Irken's concurrency is still being flushed out

  • Go supports runtime dynamic casts, while Irken does not (though it also doesn't need them)

  • Go has a _integrated in build and testing system, while Irken is just a compiler

  • Go has a module and namespacing system, while currently Irken does not

Irken only Features

Irken support parametric user defined datatypes. For example, here is the declaration for the parametric list datatype 'a represents a type parameter which may be instantiated to any type.

(datatype list
  (:cons 'a (list 'a))
  (:nil))

Irken supports Exceptions.

(include "lib/basis.scm")

(define (a)
   (raise (:mySillyException "yo"))
   1)

 (try
     (a)
  except
     (:mySillyException e) ->
        (begin (printf "caught exception: " e "\n")
               2 ;; we have to result in the same type as the try expression
        )
  )

Golang Only Features

Golang supports a structure concurrency communication mechanism known as channels.

package main
import "fmt"

func main() {
    messages := make (chan string)      // define the channel message type
    go func() { messages <- "ping" }()  // create a goroutine to send data into the channel
    msg := <-messages                   // receive data out of the channel
    fmt.Println(msg)
}

Structural Types: Irken's Row Polymorphism vs Google Go's Structural Subtyping

One of the most unique things about both Irken and Golang, is their use of Structural Typing as opposed to the more common Nominal Typing. In Nominal Typing, type compatibility is specified explicitly by name. For example, in Java we might say class Foo implements Bar, which tells us that a class will be compatible with the Bar Interface. When using Structural Typing, an object is made compatible by giving it the same structure, that is the same set of methods and fields. This is often called Duck Typing, because if a function is expecting an object to quack, then any object which can quack is compatible.

The ways Google Go and Irken use Structural Typing is similar, but not the same. There are three main differences:

  1. In Irken, all record data-structures are Structurally Typed, and records are Irken's equivalent to both structs and interfaces. In Google Go, only interfaces are Structurally Typed, structs are not.
  2. In Irken, record structures can be inferred, while in Google Go, structs and interfaces must be declared.
  3. In Irken, records are Row Polymorphic, while Google Go interfaces use a less flexible model called Structural Subtyping

Similarities

Let's start with an example of their similar Structural Typing capabilities, first in Irken:

(note: Irken's OO model is still being finalized. This is just enough code to demonstrate structural type dispatch.)

(include "lib/basis.scm")

;; optional declaration of interface
;; (typealias Whomer { 
;;    whom = ( -> string ) 
;; } )

(define (say_hello to) ;; optional type of function : ( {whom=(->string) ...} -> #u )
    (printf "hello " (to.whom to) "\n") 
   )

(define (world/whom w) "world")
(define (world/www w) "another world method")
(define (world/make) { whom=world/whom www=world/www })

(define (family/whom f) "family")
(define (family/fff f) "another family method")
(define (family/make) { whom=family/whom fff=family/fff })

(say_hello (world/make) )
(say_hello (family/make) )

And now in Google Go:

package main
import "fmt"

type Whomer interface {
   whom() string
}

func say_hello(to Whomer) {
   fmt.Println("Hello " + to.whom())
}

type world struct {}
func (w world) whom() string { return "world" }
func (w world) www() string { return "another world method" }

type family struct {}
func (f family) whom() string { return "family" }
func (f family) fff() string { return "another family method" }

func main() {   
    say_hello(world{})  
    say_hello(family{})
}

The two examples above are demonstrating essentially the same structural dispatch. Both world and family define a whom() method which they structurally share in common. Google Go requires we declare the Whomer interface, while in Irken that declaration is optional.

Compile Time Parametric Polymorphism

Let's now look at an example of Irken's Compile Time Parametric Row Polymorphism.

(include "lib/basis.scm")

(define (fa x) 
   (begin 
       (printf x.a) 
       x
    ))

(define (fb x) 
   (begin 
       (printf x.b) 
       x
    ))
(define (fc x) 
   (begin 
       (printf x.c) 
       x
    ))

(fc (fb (fa {a="1" b="2" c="3"})))
;; prints "123"

TODO:

  • add "Runtime Row Polymorphism" - aka heterogeneous lists

References

Clone this wiki locally