Skip to content
David Jeske edited this page May 9, 2017 · 21 revisions

One way to understand a language is to compare it to its contemporaries. Since C++11 templates support type-inference and Structural Typing, 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..

  • C++11 is mature, while Irken still in it's infancy with few programs written in it
  • C++11 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 C++11 has lots of 'real things' written in it. With that disclaimer aside...

Similarities

Both languages:

  • Are strong static typed
  • Can be compiled to native code
  • Support structural typing (though C++ has no polymorphic structural typing)
  • Support both functional and imperative programming
  • Support parametric types and parametric instantiation
  • Support type inference (though C++ is not global type inference)
  • Support Exceptions
  • Support compile time macro expansion

Differences

  • Irken is a Scheme like s-expression language, C++11 is a C-like syntax
  • Irken supports global type-inference, while C++11 supports inference over expressions and parametric functions
  • Irken uses a tracing Garbage Collector for automatic memory management, while C++11 relies on manual memory management and reference counted smart pointers
  • Irken structural typing is runtime Row Polymorphic, while C++11 templates are compiled parametric not runtime polymorphic
  • Irken has built-in variants with exhaustive match, while C++11 relies on libraries like boost::variant
  • Irken has pattern matching, while C++11 does not
  • Irken is stackless with stack frames in the heap, while C++11 uses a class C-stack, as a result..
    • Irken has extremely lightweight co-routines, while C++11 does not
    • Irken supports first-class continuations, while C++11 does not
  • C++11 has argument-type overloaded function dispatch, while Irken does not
  • C++11 has runtime dynamic casts, while Irken does not
  • C++11 has a module and namespacing system, while Irken does not
  • C++11 vtable virtual method dispatch is always optimal, while Irken's Row Polymorphism can require an extra indirection

Type Inferenced Structural Typing over Parametrics

Let's start with an example both languages handle somewhat similarly, Type-Inferenced Structural Typing over Parametrics. Whew, that was a mouthful. That means, both languages can parametrically instantiate functions in an expression, to the types in the expression, without type declarations, and match field access 'structurally' over those types (without a conforming super type).

Let's look at the Irken code. What this does is define a structure with fields (a b c), and calls structurally parametric functions which individually access those fields.

(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"
(fc {c="4"}) ;; prints "4"

C++11 can do the same trick, using auto and template functions.

#include <iostream>

auto fa = [] (auto x) {
  std::cout << x.a;
  return x;
};

auto fb = [] (auto x) {
  std::cout << x.b;
  return x;
};

auto fc = [] (const auto & x) {
  std::cout << x.c;
  return x;
};

int main(int argc, char **argv) {
  struct S { int a; int b; int c; };
  fc(fb(fa(S({1, 2, 3}))));

  struct G { int c; };
  fc(G({3}));
}

Irken has no NULL pointer exceptions

Like Rust, Irken does not allow NULL pointers. Instead, values which may not be present are represented by an explicit Option Variant Datatype. In Irken, variants must be unfolded using pattern matching, which exhaustively checks to make sure you handle all the cases. When the unfold of types is explicit, it is known as having isorecursive datatypes and is the source of Irken's safety from NULL pointer exceptions. Of course if for some reason you like NULL pointer exceptions, you can always make a function that unwraps and raises one if :no.

(datatype maybe   ;; Irken's option type
 (:yes 'a)
 (:no))

(define (do_something x)
   (match x with
     (:yes a) -> (something_with a)
     (:no) -> (something_because_x_was_missing)
     ;; it is an error to omit the "no" case
   ))

Irken has Pattern Matching

We already saw an example of pattern matching in handling our maybe type above. However, it can do more. For example, it can match on specific literal values, again assuring there are no unhandled cases. Also, functions may be written in dense pattern matching form, where their arguments are implicitly present in the pattern arguments. For example:

(define (if_a_then_b_else_c a b c)
  (match a b c with
    #t b _ -> b
    #f _ c -> c
  )
)

;; also may be written...
(define if_a_then_b_else_c  
    #t b _ -> b
    #f _ c -> c 
)

TODO:

  • add Irken pattern matching
  • add C++ function overloading example
  • add Existentially Quantified Row Polymorphism vs Interface Subtyping
Clone this wiki locally