5 ms·
For me, no templates + no exceptions = DOA.
by fbomb 13y ago
For me, no templates + no exceptions = DOA.
- deleted 13y ago[deleted]
- jeremiep 13y agoExceptions I can easily live without; Haskell's monads provide a much better mechanism for error handling (Maybe, Either, IO, etc).
- klibertp 13y agoYou have generics^2 if you're using Haskell, so it's no wonder they are able to replace exceptions ;)
- masklinn 13y agoGo has exceptions (panic/recover). They're pretty bad, you shouldn't use them (just as you generally shouldn't use exceptions in Erlang) and some in the Go community downright refuse to accept that they exist, but they're there.
- TylerE 13y agoTemplates are a sad hack in place of true hygenic compiler macros.
- marshray 13y agoMacros are the sad hack. Templates can express compile time assertions.
- TylerE 13y agoI believe you misunderstand me. I'm not talking about preprocessor macros, but TRUE compiler macros ala Lisp or Clojure, which can bring the full expressiveness of the language to bear on the task at hand, and generate program code as a return value. Consider the following example, from Clojure, which implements a C-style for-loop (defmacro for-loop [[sym init check change :as params] & steps] (cond (not (vector? params)) (throw (Error. "Binding form must be a vector for for-loop")) (not= 4 (count params)) (throw (Error. "Binding form must have exactly 4 arguments in for-loop")) :default `(loop [~sym ~init value# nil] (if ~check (let [new-value# (do ~@steps)] (recur ~change new-value#)) value#)))) Syntax primer: The code runs at compile time, forms (nested parenthized groups) that are prefixed with ` are the output, ~var means to substitute the _value_ var from the macro invocation, and var# means create a new anonymous variable var, guaranteed not to clobber or shadow any existing variable. For instance, given out macro defined above, say we make the following call: (for-loop [i 0, (< i 10), (inc i)] (println i)) The code generated by the compiler for that invocation is: (loop* [i 0 value__95__auto__ nil] (if (< i 10) (clojure.core/let [new-value__96__auto__ (do (println i))] (recur (inc i) new-value__96__auto__)) value__95__auto__)) You can see how A: all the error checking is done at compile time and comes at no runtime cost B: how the `-quoted code in the original macro gets "filled in". C: How the arguments to the macro are not evaluated by the macro call or the substition until they are actually used. Point C is quite powerful since it means that macros can be used to create arbitrary control structures that are fully as powerful and general as anything in the core or stdlib - and in fact many of those are implemented as macros.
- marshray 13y ago(not (vector? params)) I see that you are indeed able to access some amount of type information in your macro system. Well done!
- TylerE 13y agoI thought I made it clear. The macro system is not some subset, it is the full language with all the capabilities that brings with it, including type functions, reflection, etc. You can even do I/O in macros, whatever you want. The full language is available.
- marshray 13y agoForgive me. The term 'hygenic macro' has historically been associated with Lisp and Scheme which were not known for the availability of type information at compile time, because they are dynamically typed and often did not have a compile time.
- TylerE 13y agoFair enough. Clojure really is a wonderful language. It's sort of a "Javascript: The Good Parts" for Lisp - they kept (and expanded on) that wonderful expressiveness, while doing away with 50 years of dogma that held on to stuff like gen-syms, car, cdr, and singly-linked lists as the one-true-datatype.