read


read
or learn more

Enfield: a programming language designed for pedagogy

Jan 21, 2013

Today I would like to introduce an idea that I’ve been playing around with as a thought experiment for years, but that has finally become a reality. Imagine a programming language designed specifically for teaching young computer science students a solid foundation in sound computer science topics as well as practical techniques useful in creating rock-solid industrial systems. Below, I’ll outline the features of Enfield.1

enfield

the Enfield logo

Syntax

To start, I’m strong believer that when learning new, and at times complex topics it’s outright detrimental to overload students with frivolous syntax rules. Therefore, Enfield is designed with minimal syntax rules and what’s more minimal than a Lisp like syntax. An example function definition in Enfield is as follows:

(define (fibo number)
  (letrec ([f (lambda (number n i)
                (if (<= number 0)
                    i   
                    (f (- number 1) 
                       (+ n i) 
                       n)))])
    (f number 1 0)))

(fibo 500)

;=> 1394232245616978801397
    2438287040728395007025
    6587697307264108962948
    3255716228632906915576
    58876222521294125

There are a few interesting points about this snippet:

  1. A Lisp syntax
  2. Bignums
  3. Tail-recursion
  4. Lexical scope

In each case a pedagogist can take the opportunity to deeply explore these important topics. However, focusing again on syntax for a moment, while I do think that a simplified syntax is best, it’s important to allow maximum flexibility. It would be nice for Enfield to provide macros in additional to lexer and parser hooks (another chance to dive deeply here) in order to form the syntax to one’s will, allowing a multitude of syntactic forms. One interesting possibility, and one that I think is sorely lacking from CS education, is a special form of Enfield that allows a student to write essays in a textual language containing embedded source code. Too often CS education focuses on mathematical formalisms and code to the dismissal of the spoken and written word — Enfield can help!

Essential building blocks

Key to any college programming course is that the language of choice provide the essential building blocks of computation. Ideally, an introductory course would require students to not only learn a language, but to also create an interpreter for a subset of the language using the language itself. Enfield should therefore provide a set of basic building blocks useful for building Enfield in Enfield. Features such as metaprogramming, code as data, concurrency primitives, continuations and parsing libraries are just a few that would allow a deep understanding of not only Enfield, but language design and implementation in the abstract.

A plethora of libraries

While it’s a great idea to keep the syntax and logical footprint of Enfield small, in no way should the language be minimal in it possibilities. A language for learning should provide a large spectrum of possibility, from offering easy exploration of the untyped lambda calculus to first-class access to performant linear algebra libraries via its packed offerings, package repositories and popular source repositories.

Hardcore IDE

A first-class IDE is essential to the learning process. As amazing IDEs like LispWorks, Mathematica Notebooks and ObjectStudio have shown, there is amazing potential in a programming environment tightly integrated with the language on which it operates. A Enfield IDE should have the standard fare, including: breakpoints, value inspection, import resolution, expression evaluation and all of the other features found in modern IDEs. Additionally, a first-class graphical capability allowing students to plot graphs and explore the shape of algorithmic execution are key.

dr

An illustration of a ‘hypothetical’ IDE session of a student creating a Tetris game.

There is a lot to learn from new IDEs technologies like Light Table in developing a Enfield IDE.

A plethora of paradigms

While Enfield supports functional styles, and any curriculum should use it as the primary focus, it should also support numerous paradigms.

Query languages and logic

Logic programming languages should be readily available or easily made using Enfield. Ideally a curriculum built around Enfield would include sections on miniKanren (supplemented with appropriate miniKanren literature, Prolog, SQL and Datalog. A solid foundation in logical thinking and declarative programming is key for any computer scientist.

OOP

In addition to covering the standard academic topics such as functional programming, logic and continuations, Enfield should allow industry-proven object-oriented techniques. A simple example might look as follows:

(define animal-interface (interface () say))

(define cat% (class* object% (animal-interface)
               (super-new)
               (define/public (say)
                 (display "meeeeew!"))))

(define tom (new cat%))
(send tom say)
;; meeeeew!

This is a work in progress.

Metal

Lest I be accused of favoring high-level programming over bare metal techniques, I should say that every programmer should have exposure to low-level programming. Ideally Enfield would have a first-class FFI used to access C-level libraries created by the students. A different world unfolds when one needs to manage memory manually and tweak algorithms to their utmost to milk every last bit of speed. Enfield should facilitate that experience rather than deny.

Other paradigms

In addition to the paradigms above, Enfield should also support others including, but not limited to: prototype-based object programming (sample below), dataflow, imperative and parallel programming.

(define-object account (*the-root-object*)
  (balance set-balance! 0)
  ((payment! self resend amount)
   (self 'set-balance!
         (+ (self 'balance)
            amount))))

(define a1 (account 'clone))
(define a2 (account 'clone))

(a1 'payment! 100)
(a2 'payment! 200)

(a1 'balance)
;; => 100

(a2 'balance)
;; => 200

(a1 'payment! -20)
(a1 'balance)

Of course, every section on a given paradigm should include deep discussion and exercises around the benefits and drawbacks of each paradigm. Using a multi-paradigm programming language as a teaching tool allows students to experience a wide breadth of paradigms allowing them to develop a true understanding of what each offers, its drawbacks and its strong points. The last thing we want are programmers versed in only one or two paradigms.

Creating robust software

A college curriculum is a delicate balance between academic and industry focuses. I’m of the opinion that a well-balanced curriculum focuses on core concepts, paradigms and histories to start and then only diving into “real-world” concerns for senior year projects or courses and graduate programs. However, along the way Enfield courses could indeed introduce and foster an understanding of techniques used for creating robust, real-world systems. As with the lessons on paradigms, a college curriculum should feature deep discussions and essays outlining the short-falls and benefits of learned techniques outlined below. It would be a tragedy to produce programmers who think that any one of the techniques below is wholly sufficient in ensuring robust software systems.

Unit testing

An Enfield unit testing framework could be developed from scratch with supplemental material from luminaries such as Kent Beck. Any included or available Enfield unit test framework should provoke much in-class respectful debate; something else sorely lacking from typical college curriculum and Internet message boards.

Contracts

A little used but powerful technique for software verification is the use of software contracts; or patterns for declaring relation function and method input/output constraints and object invariants. A thorough investigation of contracts on functions (including higher-order functions) compared to those on classes involved in hierarchies is fertile ground for deep discussion and debate. A simple example of what a contracts system might look like would be as follows:

(provide
 (contract-out
  [argmax
    (->i ([f (-> any/c real?)] [lov (and/c pair? list?)]) ()
         (r (f lov)
            (lambda (r)
              (define f@r (f r))
              (and (is-first-max? r f@r f lov)
                   (dominates-all f@r f lov)))))]))

(define (dominates-all f@r f lov)
  (for/and ([v lov]) (>= f@r (f v))))

(define (is-first-max? r f@r f lov)
  (eq? (first (memf (lambda (v) (= (f v) f@r)) lov)) r))

Contracts in Enfield should be applicable post-facto so that students can apply constraints to previous exercises or external libraries. This would be a fun and challenging.

Static typing

Enfield wouldn’t be complete without the ability to provide some level of static typing. Ideally, its static checks, like contracts, should be applicable to existing libraries either piecemeal or in whole. The exercise of applying static types to functions created from whole-cloth or pre-existing should provide a nice counter-point to the dynamic experience provided by Enfield by default. Static checks in Enfield would not look very different from regular source:

(: sum-list ((Listof Number) -> Number))
(define (sum-list l)
  (cond [(null? l) 0]
        [else (+ (car l) (sum-list (cdr l)))]))

Class focus on topics revolving around polymorphic dispatch, gradual typing, subtyping and union types should provide heated discussion.

Practical concerns

Rather than a purely academic language, Enfield should be reasonably practical. As a senior project or special course students could engage in building a webserver using pure Enfield. They would start with as few lines of code as possible…

(define (start req)
  (response/xexpr
   `(html (head (title "Hello Cleveland!"))
          (body (p "Hi!")))))

… and build up to more complicated offerings. Maybe using the robust FFI a student could create Node.rkt! Additionally, Enfield should be simple enough to allow the student to write a subset of it to target the web-browser via JavaScript.

Conclusion

I’ve outlined a complete programming language, runtime and tools that would, could and should be used in colleges across the world. From my perspective a multi-paradigm approach is ideal to provide a breadth of experience, to generate class discussion and debate and to minimize the tangential complexities that comes from switching languages.

If only Enfield were real

If you’d like to discuss Enfield, its features or any of the ideas presented herein then feel free to comment on this post or email me at the address at the top of my blog.

:F

thanks to Brian T Rice for inspiring this post with a well-timed comment on the Twitters

update feb.2013: I have completed the implementation of Enfield! The complete implementation of Enfield (in Racket) is on Github. Patches welcomed!


  1. Enfield is a fictional tennis academy in the novel Infinite Jest by David Foster Wallace — a school where rackets are used to to great effect. 

21 Comments, Comment or Ping

  1. Thanks for nice ad :-)

    Naturally I have been thru interpreters, continuations and mini-OSes in a freshman course and my Applied Math colleagues at the time really wanted a connection to fast algebra packages. (If only I had understood them properly).

    There is a reason, however, we discovered the need for an on-ramp to Racket via teaching languages. But everything else is indeed done with a complete, full-fledged Program Design and SE curriculum in mind.

    So thanks again.

  2. configurator

    Racket syntax is not “simple”. It’s not easy for a beginner to understand. There is a lot of syntax, and it’s extremely complicated. The lexer is simple. But the syntax isn’t. Polish notation is confusing to a beginner, and those parenthesis are “weird”. Why “(add 1 2)”? “add 1 2”, “add(1,2)”, “add 1,2” are all far clearer. The reason it uses a hard-to-interpret syntax is to keep the syntax simple, but especially to a beginner, simple means something completely different when you look at it from the user’s side.

    That said, the fundamentals of functional programming, the ones that are so easy to learn using a Lisp, will change every piece of code the developer will ever write, to the better. I believe Racket is an awesome language to learn as a first language, but saying it has a simple syntax is a fallacy.

    I guess what I’m saying is Racket is awesome but I’m tired of hearing about its “simple” syntax instead of its real advantages.

  3. @configurator

    I guess what I’m saying is Racket is awesome but I’m tired of hearing about its “simple” syntax instead of its real advantages.

    The comment about simple syntax was 1-2 sentences out of a multi page blog post about its real advantages. Did you stop reading once you found something to be offended about?

  4. @matthias

    There is a reason, however, we discovered the need for an on-ramp to Racket via teaching languages. But everything else is indeed done with a complete, full-fledged Program Design and SE curriculum in mind.

    I’ve read your “The Structure and Interpretation of the Computer Science Curriculum” [pdf link](http://www.ccs.neu.edu/racket/pubs/jfp2004-fffk.pdf) and wonder if there has been an update since its publication?

    Thank you for reading and taking the time to comment.

  5. Patrick Logan

    Any time anyone says “simple”, one should probably substitute “familiar” to see whether that works without upset.

  6. Lance Bachmeier

    While I support the use of s-expressions, I believe an explicit syntax is important. In Lua, this

    (if (<= number 0) i (f (- number 1) (+ n i) n))

    becomes

    if number <= 0 then return i else return f(number-1,n+i,n) end

    It’s confusing to have to realize when a piece of code is being evaluated and returned vs just evaluated. Further, the if is followed by two arguments, one and only one of which returns something.

    You mention the FFI. LuaJIT is good in that regard because (basically) you don’t write any glue code. It’s trivial to pass data to and call C library functions. Want a linear algebra library? No problem. From what I’ve seen of Racket, that’s not the case.

  7. configurator

    @fogus, I didn’t stop reading. But the first thing you mention, the first thing anyone “selling” a Lisp to beginners always mentions, is it having “simple” syntax. And that is only a selling point to somebody who’s already bought into it like you or me.

    The rest of your points are spot on. I didn’t mean to imply anything about the entire post – it just always bothers me when people mention the syntax as being such a superb property. Macros, and other things this syntax enables, are great features but the syntax itself is not.

    P.S. I’d also add that the way functional programming techniques can transfer to most any other language is an important aspect that should also be mentioned, though preferably by someone more eloquent than me.

  8. Sam Tobin-Hochstadt

    Fogus:

    The most recent update on Matthias’ thoughts on the curriculum can be seen in the following sources:

    1. His talk at ICFP 2010/SIGCSE 2011: “TeachScheme!: A Checkpoint”. Slides available from: http://www.ccs.neu.edu/home/matthias/presentations.html Video available here: http://dl.acm.org/citation.cfm?id=1863563&picked=formats

    2. The second edition of HtDP, in progress: http://www.ccs.neu.edu/home/matthias/HtDP2e/

    3. The ICFP 2009 paper on World and Universe: http://www.ccs.neu.edu/racket/pubs/icfp09-fffk.pdf

    4. Matthias’ talk at RacketCon 2011; slides and video linked from http://con.racket-lang.org/2011/

  9. @Sam

    Thank you for the links. I appreciate it.

  10. alejandro varela

    i love scheme! nice post!

  11. “Simple” does not mean “easy” or “familiar”. It means “without complexity”. The Lisp syntax is definitely simple. It’s probably not the easiest.

    For more information on the difference, I recommend “Simple Made Easy”, a presentation by Rich Hickey.

    http://www.infoq.com/presentations/Simple-Made-Easy

  12. John

    @Lance Bachmeier

    Regarding to FFI: LuaJIT also has FFI, just like Racket, so I’m seeing any benefits of LuaJIT over Racket. On both systems, with FFI, you pass data on C library functions without glue code…

    Regarding to syntax: some people prefer explicit syntax (e.g. Pascal, Lua) and some more terse (C, LISP, Haskell), it is a matter of taste. However, benefits of s-expressions is that you can add your own constructs; e.g. allegro lisp has :then and :else so it can be written as:

    (if (<= number 0) :then i :else (f (- number 1) (+ n i) n))

  13. John

    Fix: …so I’m not seeing any benefits of LuaJIT over Racket. :)

  14. Bill

    Perhaps Enfield would be more aptly named Narcissus.

  15. Logo

    I… I… I just don’t get the logo…

  16. agumonkey

    About syntax issues, it would be fairer~ to say that ‘f(x,y)’ can appear simpler because of previous exposition, not because of inherent structure.

    Lisp is “simpler” since it has less classification (no need for commas) and builds bottom-up.

    At the end there will be a lot of syntactic classes (forms, application, literals, …) like most other languages but the basic block is still that one way to group things (a b …) which plays more at the semantic level than the syntactic one.

    As an anecdote, I failed an ADA exam because I lost 2 hours searching how to get a char out of a string instead of a string of length 1. The answer was to put a ‘ somewhere at the end. Everything but simple.

    Having the system revolving around a flat functions/forms space has some qualities.

    Enough redundant rant.

  17. Yes, whenever anybody suggests using a Lisplike language in teaching, the first objection is always the “unnatural, unfamiliar” syntax. Why is it unnatural and unfamiliar? Because you already know another syntax to do the same thing.

    So I start my course (and my textbook) with image manipulation: scaling, rotation, reflection, vertical and horizontal concatenation, etc. Most people don’t already know a syntax for manipulating images, so Scheme syntax doesn’t strike them as unnatural. By the time we get to arithmetic, students have already been using the syntax for several weeks: I say “The syntax for calling an arithmetic function is the same as the syntax for calling an image function,” assign a few exercises, and they get it in a day or two.

    Scheme syntax is a much bigger problem for teachers trying to protect their students from it than for the students themselves.

  18. ben w

    “Any time anyone says “simple”, one should probably substitute “familiar” to see whether that works without upset.”

    Why? Simplicity and familiarity have nothing to do with each other. We can become familiar with horribly complex things; they won’t therefore be simple. The guy who complained that racket’s syntax isn’t simple was, in fact, complaining that it isn’t familiar (his complaint was basically “parens are weird and so’s prefix notation”); he should have substituted “familiar”. But someone claiming that racket’s syntax is simple shouldn’t.

  19. agumonkey

    @ben w, is this inspired by Rich Hickey “Simple vs Easy” ?

    1) After enrolling on coursera proglang online course, I’ve witnessed interesting things: sml is so tiny, it will make lisps/schemes fat. You will run for sexp aware edition like emacs/paredit.el to avoid headaches.

  20. Su-Shee

    Other IDEs to get inspired by: Smalltalk itself (Pharo these days), RStudio (R shell + visualization/charts etc + all kinds of other IDEish things), iPython has a similar concept.

  21. Ivo

    It’s worthwhile to point out that somewhat later in 2013, some of the contributors to Racket came out with Pyret [1], a language (implemented in Racket) specifically intended to be used for teaching. The Hacker News [2] and Reddit [3] discussions are interesting, because the Pyret team contributes to the discussion on several design decisions.

    Many of the features mentioned are indeed present, perhaps with the notable exception of not using Lisp syntax, which they decided against based on pretty thorough research.

    [1] http://www.pyret.org/ [2] https://news.ycombinator.com/item?id=6701688 [3] http://www.reddit.com/comments/1q8zzk

Reply to “Enfield: a programming language designed for pedagogy”