7 ms·
A cursory look at meta-programming in Nim
- kbd 11y agoIt's a small thing, but I'm so glad they renamed it to "Nim". Its prior name carries such a negative connotation, while just shortening that gave a name that's cute and simple.
- vezzy-fnord 11y agoI'm one who actually preferred Nimrod, but it's done by now.
- david-given 11y agoAh --- I didn't know this was Nimrod! I remember looking at that a few years ago and thinking 'this is awesome but not quite ready yet'. I need to have another look at Nim. It even looks like it's in Debian!
- jwecker 11y agoFun fact- Nimrod means mighty hunter. The negative connotation came from early Bugs Bunny cartoons where he applies the name sarcastically to Elmer Fudd.
- sigzero 11y agoAlso a very cool future sentinel in the X-Men comics.
- evilduck 11y agoKind of. https://en.wikipedia.org/wiki/Nimrod https://en.wikipedia.org/wiki/Nimrod There's definitely a much older negative connotation than the Bugs Bunny usage.
- jessaustin 11y agoYou don't like big waterfall projects like the Tower of Babel? You must be one of those microservices people... b^)
- Dewie3 11y agoThe voices of American programmers are loud and many.
- platz 11y agoAt least we still have Coq
- Dewie3 11y ago`git` also carries negative connotations. But at least that was intentional.
- kazinator 11y agoWay too cumbersome, sorry. TXR Lisp: @(do (macro-time (defun abc-proc (n) ^(defun ,n () (pprinl ',n)))) (defmacro abc-procs (. n) ^(progn ,*[mapcar abc-proc n])) (abc-procs a b c) (defun exec (order callbacks) (each ((i order)) [[callbacks i]])) (exec '(0 0 1 2 1 2) '(a b c))) $ txr test.txr a a b c b c Variation on exec: (defun exec (order callbacks) (mapdo (op [callbacks @1]) order))
- andybak 11y agoYes but on the plus side there's a lot fewer parentheses.
- ldlework 11y agoYou were down-voted but I secretly agree. wait - oops. :)
- kazinator 11y agoIf you're counting tokens, you should count all of them: all symbols and punctuation, as well as any whitespace outside of a string literal that cannot be replaced by a single space character without affecting the syntax.
- andybak 11y agoSo APL is your favourite language then? :) You should somehow measure cognitive load. Of course it should be measured on someone fluent in that language - but there should be an adjustment to factor in the cost of becoming fluent. :)
- kazinator 11y agoAPL is about being obsessive with character count. We can turn any language into "APL" by giving the core functions one-letter names and using the lack of whitespace between them in some semantic role like chained application or whatever. Hey look, "FUBAR". Take the first item, unwrap the list, bind it to function A as the first argument, then reverse! This kind of character-level reduction I'm not interested in at all; It's computer science puberty. I never said "way too long" but rather "way too cumbersome". What is cumbersome in the Nimrod is the awkward encapsulation. For example, we have to create a special kind of list of statements with a special constructor. This list is a "bag-like" container with an .add method. Yuck!
- shasta 11y agoI think the author should post a follow-up after he's tried to do substantial work with this style meta-programming. My guess is that you want to keep templated code to an absolute minimum.
- ldlework 11y agoYou were down-voted but I actually agree. I did conclude the article by saying that templates seem really nice for closing the gap on refactoring code that not even generics could wrap up. So the intention was to convey that templates are really a last resort secret weapon. They just also seem to be pretty easy to understand :)
- hzhou321 11y agoOr, with a text based meta-layer (MyDef): import macros $(for:A in A,B,C) proc $(A)() = echo "$(A)" proc execute(order: seq[int], callbacks: seq[proc]) = for i in items(order): callbacks[i]() execute(@[0,0,1,2,1,2], @[A, B, C])
- kazinator 11y agoYou might as well use the POSIX shell to write your code: cat <<END $(for x in A B C; do echo "proc $x() = echo \"$x\""; done) proc execute(order: seq[int], callbacks: seq[proc]) = for i in items(order): callbacks[i]() execute(@[0,0,1,2,1,2], @[A, B, C]) END
- hzhou321 11y agoIt worked! Now how do I incorporate this into my tool chain (Makefile)?
- kazinator 11y agoBelieve it or not, I actually did this years ago, and I have the Makefile somewhere. [... search ...] Found the rules! %: %.ct cpp -P $(shell env | sed -e "s/.*/-D_ENV_'&'/") $< > $@ %: %.st ( export __FILE__=$< ; echo "cat <<!" ; cat $< ; echo "!" ) | bash > $@ %: %.mt rm -f $@.err m4 -D__FILE__=$< $(shell env | sed -e "s/\([^=]*\)=\(.*\)/-D'_ENV_\\1=\\2'/") $< > $@ if [ -s $@.err ] ; then cat $@.err ; exit 1 ; fi rm -f $@.err Explanation: this gives you three "flavors" of preprocessing. ".ct" files are "C preprocessor templates"; they are put through cpp. ".mt" files are M4 templates: M4 is used. And ".st" are shell templates; they use shell here-doc syntax. The shell templates do not have to have any "cat <<" or "!"; this wrapping is added by the Makefile. Of course, you can't have a line consisting of ! in these files; you have to escape such a thing if it occurs. Additionally, for .ct and .mt files, all environment variables are turned into macros in that language, with their names mapped to the the _ENV_* namespace. For .st and .mt files, the __FILE__ macro is established which expands to the file name (the C preprocessor has this built-in). I used this in an embedded Linux distro that I build from scratch (targetting MIPS embedded hardware). It was used for generating some of the textual materials in the target file system tree. For instance /etc/hosts was generated from a .st template, and populated using a $(for ...) loop. Yes, I do Lisp and I do stupid. :)