---
title: "SU-CS143 APR032025"
source: https://www.jemoka.com/posts/kbhsu_cs143_apr032025/
date: 2025-04-03
---

how to design a language: &ldquo;why don&rsquo;t we just make a truing machine?&rdquo; tl;dr: &ldquo;writing code in a Turing Machine takes a while, writing it in C++ takes a little less while.&rdquo;
languages fills a void: makes something previously difficult/impossible easy good languages vs. language design needs are orthogonal things why do we not change languages? rewriting code is hard languages with many users are replaced rarely &mdash; popular languages are ossified so people just go start new niches language vs. ends SQL: query optimizations by separating data query vs. access pattern (inserting indexes w/o rewrite code) Python: library composition / FFI Haskell: proofs and type safety Rust: security language design no universally accepted metrics for design claim: &ldquo;a good language is the one that people use&rdquo; (&ldquo;I don&rsquo;t really buy that, because otherwise PHP would be the best language&rdquo; - Fred 2025) abstraction abstraction &mdash; detaching high level problems from functional details, &ldquo;selective ignorance&rdquo;.
key is information hiding: expose only the essential things leave high level properties To create abstractions, we&hellip;
use languages and compilers: create high level code with few dependencies specific to machines use functions: allows users to create interfaces to behavior use modules: export interfaces and hide implementations use classes / ADTs: bundle data with its operations some good ideas types &ldquo;types is used to enforce abstractions&rdquo;
FORTRAN: scalars, arrays, and that&rsquo;s it LISP: no static type distinctions insight: types are helpful!
they let you express and enforce your own abstractions they let the compiler report frequent errors &hellip;up to complete safety (Java, Haskell, Lean, etc.) helps guide optimization reuse Exploit common platter in software systems (to get mass-produced components and reuse).
type parameterizations: (List[int], List[double]) classes and inheritance: derived classes C++ and Java has both! During class derivations, good approaches mostly emit the code multiple times for each specialization. Inheritance allows:
specialization of existing abstraction extension, modification, hidden behavior, etc. COOL We will implement COOL in this class; written by Alex in the 90s.
abstraction static typing inheritance strict object orientation (everything is in a class) memory management (with GC (oh no)!) light metaprograming A Tour class Point { x : Int &lt;- 0; y : Int &lt;- 0; }; Inside class Main, there&rsquo;s a special method main. All COOL code lives inside this evaluation.
class = {attributes, methods} instances of classes are objects class Point { x : Int &lt; - 0; y : Int; (* could have default values *) }; Objects are thought of as records
digraph { graph [bgcolor=transparent]; node [fontcolor=white, color=white, shape=none]; edge [fontcolor=white, color=white]; a [label=&#34;{{x|y} | {0|0}}&#34;, shape=&#34;record&#34;]; } classes Classes can only contain features = {attributes, methods}. Here&rsquo;s a class both types of features:
class Point { x : Int &lt;- 0; y : Int &lt;- 0; movePoint(newx : Int, newy : Int) : Point { { x &lt;- newx; y &lt;- newy; self; } --- this is a block }; }; Cool, therefore, is a an expression based language (a la Rust).
Key: one block per expression; notice how we had to surround the block in additinal curlies.
Some facts:
shadowing is allowed methods are all GLOBAL/PUBLIC attributes are all LOCAL/PRIVATE (make getters) all attributes of a class are visible to all methods of that class (just use the name) allocation When we have a method, we put in the field a pointer to the actual function.
digraph { graph [bgcolor=transparent]; node [fontcolor=white, color=white, shape=none]; edge [fontcolor=white, color=white]; obj [label=&#34;{{x|y| }|{0|0|&lt;here&gt;*}}&#34;, shape=&#34;record&#34;]; obj:here:e -&gt; movePoint; } As an optimization, if multiple instances exist, we create a method table or a vtable which points to all methods.
digraph { graph [bgcolor=transparent]; node [fontcolor=white, color=white, shape=none]; edge [fontcolor=white, color=white]; obj [label=&#34;{{x|y| }|{0|0|&lt;here&gt;*}}&#34;, shape=&#34;record&#34;]; methods [label=&#34;{methods|*}&#34;, shape=&#34;record&#34;] obj:here:e -&gt; methods:e -&gt; movePoint; } inheritance class ColorPoint inherits Point { color : Int &lt;- 0; movePoint(newx : Int, newy : Int): Point {{ color &lt;- 0; x &lt;- newx; y &lt;- newy; self; }}; }; notice how movePoint still returns a Point because we don&rsquo;t have multiple dispatch.
types Every class is a type.
base classes: Int, Bool, String, Object (root of the hierachy) everything must be declared (the complier infers types) type checking x : A; x &lt;- new B: is well typed if A is an ancestor of B.
invocation Consider:
p : Point; p &lt;- new ColorPoint; ... p.movePoint(1,2); -- this should invoke the ColorPoint version So, consider:
e.m(a) the evaluation semantics:
evaluate arguments a evaluate e, the receiver find the class of e find code of m (to jump through the method table to the methods of e to find m) &mdash; we have to do this dynamically because we don&rsquo;t know (see example above) whether this is a point or color point or whatever bind self and arguments (such as a, the formal parameter, to the actual parameter, x) jump and run the actual method expression language, so we don&rsquo;t have&hellip;
arrays floats exceptions
