6 ms·
My Language Is More Agile Than Yours: A Study of Arc
- axod 17y ago>> printIfNotNull(foo.getBar().getName()); // pointless method >> in arc ... >> ... aif is a macro that expands this code to >> >>(let it ((foo 'bar) 'name) >> (if it >> (print it))) Why is a macro not pointless, while a method/function apparently is? I don't think that makes sense personally. Surely a macro is just a function that's been inlined - which may be better, depending on if you're optimizing for speed or size. Anyone explain? Also, I'm not sure if this was being serious or not: >> Priorities in language design >> A Language Should ... If it was serious, it completely depends on what problem you're trying to solve as to what priorities you're going to have.
- andreyf 17y agoBecause aif works with any expression, not just print. Granted, in a functional language like JS, one could say: ifNotNull(foo.getBar().getName(), function (it) { print it; }); but "function (it)" and all of the "().{}" are still blub. As PG points out on the arclanguage forums [1], an even simpler way of putting it is: (only.print foo!bar!name) Which, without the Arc-specific syntax sugar, is: ((only print) ((foo 'bar) 'name)) So "only" is a modifier that makes a verb (function) happen only if its argument is truthy (think Python decorators). Note to PG: the dot operator is undocumented, and f.g.h.3 does not at all what I expect - looks like it does (f g h 3), whereas I expected (f (g (h 3))), in the spirit of Python decorators. 1. http://arclanguage.org/item?id=9350 http://arclanguage.org/item?id=9350
- axod 17y agoIn js, if printIt is a function already defined, you don't need the function(it){} ifNotNull(foo.getBar().getName(), printIt); Granted, in java passing functions around is more of a pain.
- klipt 17y agoYep, a lot of the features mentioned in the presentation are possible with just first class functions, although the syntax will be messier (but arguably more consistent). The strength and danger of macros is in allowing you to create new syntax, skipping all the extra blub that made your code conform (consistently) to the original parser. What I'd like to know though is how much humans depend on that blub. It's one thing to write your own macros and use them consistently, or even for a group of people to come up with macros and use them consistently. But if people work independently, what happens when you read someone else's code and find they've come up with macros to do the same things as yours do, but with different names and different usage conventions? Wouldn't that be a bit like having every scientist invent their own jargon? Either humans can learn to translate that kind of thing on the fly, or they can't, and lisp with heavy macro usage will only ever be useful as a solo (or small group) language.
- andreyf 17y agoWouldn't that be a bit like having every scientist invent their own jargon? I don't know about "all scientists", but mathematicians do precisely this all the time! Each paper and each textbook begins by defining what symbols mean what, and which terms are used how. But a textbook is about as big a consistent block of terminology as you'll be able to find. In a grander sense, terms are constantly re-purposed and evolving over time [1]. Something as simple as "⊂" will mean "subset" in one book, and "strict subset" in another. In my experience, the older the book, the more divergent it'll be from current usage. This suggests that the language of mathematics evolves over time, precisely because every practitioner can change the language and push for her own terminology. There is no "Mathematics corporation" which creates languages people would be forced to choose from - no mathematician, no matter how great, would suggest that he would know what the "eternally right way" of expressing mathematics is. This is especially apparent in more exploratory parts, where definitions start being named after their authors. I, personally, look forward to a time when I get to choose between a Norvig-garbage-collection and Graham-garbage-collection for each object in my code. We're in this ridiculous stage of software engineering, where, if you're using Java, you have to do garbage collection The Java Way (you get to set a couple of settings, but that's it). No mathematician would ever be forced to make the decisions that Sun's engineers were forced to make when designing Java, because nobody could make those decisions correctly - how programs must interact with the call stack, the mechanics of method invocation, etc. 1. "Compactification" comes to mind as an example: http://en.wikipedia.org/wiki/Compactification_%28mathematics%29 http://en.wikipedia.org/wiki/Compactification_%28mathematics...
- pg 17y ago(def only (f) (fn args (if (car args) (apply f args)))) The . and ! operators got redefined so that x.y.z is ((x y) z) instead of (x y z). I think I posted the source on arclanguage.org.
- CatDancer 17y agohttp://arclanguage.org/item?id=9219 http://arclanguage.org/item?id=9219
- hlidotbe 17y agoThat's what I was wondering too. Almost all examples use macro. And for this one the argument that you need a temp variable to avoid redundancy is kind of moot since his macro use one too (I'm not familiar with the syntax so I might be wrong)
- utx00 17y agoa macro can be pointless sure. mostly if the same thing can be accomplished with a function (most of the time, but not exactly). a macro is not a function that's being inlined.
- sker 17y agoIs this similar for all the dialects of Lisp? Because if it is, I might start learning one tonight.
- Raphael_Amiard 17y agoThe macro definition abilities is mostly similar for most popular lisps around, Common Lisp, Scheme, Clojure
- andreyf 17y agoI like the argument, especially using the word "blub" to describe the cruft that is inherent to the language, but I have to question how much it's preaching to the choir, and how much will penetrate people who don't already agree. Maybe it's indicative of my crowd and not the community at large, but even the smartest people seem to hit up Haskell-for-fun and Python-in-practice over Arc. It's hard to call them blub-programmers, since they're genuinely curious, hard-working people...
- klipt 17y agoHaskell isn't exactly blub; between the first class functions and the custom monads it's quite possible to create custom languages. E.g. the parsing library Parsec: http://book.realworldhaskell.org/read/using-parsec.html http://book.realworldhaskell.org/read/using-parsec.html
- deleted 17y ago[deleted]
- gaius 17y agoHaskell-for-fun and Python-in-practice I am in exactly that camp, tho' I do fully intend to use Haskell for real once it becomes viable to do so. It's like the Python Paradox all over again.
- patio11 17y agoThe point about string concatenation is, umm, I don't want to say "wrong" because wrong sounds argumentative so I think I'll pick a circumlocution like "contrary to fact" or "a bedtime story to scare CS101 students with, second only to 'use left shift instead of dividing by two, it is faster'". Also in modern Java (and Ruby) projects you can typically write: logger.debug("This is a stupidly expensive calculation: " + stupidlyExpensiveCalculation()) and it will get executed regardless and logged only if your logging settings, which are configured elsewhere and can be toggled with a mouseclick, are set to log the debug level. Now, don't get me wrong, Arc's solution of defining a macro which checks to see whether your debug setting, which is defined elsewhere and can be toggled with a mouseclick, is on or not is a good idea. Its just not a revolutionary new idea for us wizened Big Freaking Enterprise App Ugly Language Programmers. Nor was it really that new in the halycon days of yore when Log4j crawled out of the primordial ooze.
- gaius 17y agoWe get this for free in Haskell.
- klipt 17y agoNot exactly free ... laziness and the resulting thunks do use up extra processing time and memory. But in many cases it is a price worth paying. http://www.cs.chalmers.se/~rjmh/Papers/whyfp.html http://www.cs.chalmers.se/~rjmh/Papers/whyfp.html
- smikhanov 17y agoAgree. isDebugEnabled() method is used to scare people since 2001, probably around the time when it came out of common use. Macro that is being used for exactly that is not a distinguishing feature of the language. Java proponents may come out with, say, accessing array in constant time (how many car/cdr pairs you need for that?) Important is that neither of the described facts add something to the value of one language against another and usually serve only as a basis for speculation. Edit: when I'm saying "went out of common use", I mean that elegant alternatives like logger.log("Expensive calculation is going to be: {0}", objectWithExpensiveToStringMethod); have emerged.
- matth2 17y agoIf it takes X characters to achieve something in language A, and X*4 to achieve the same thing in BLUB, I don't think this means BLUB is 4 times slower to develop in than A. When I develop software, most of the big delays, and excuses for procrastination are in forcing my brain into action over the higher level concepts. I find a lot of the extra lines of code required when using BLUB can be written at high speed, with little "hurt" to the brain. I'm not saying BLUB is just as fast to develop with, I'm just saying the benefit isn't as good as number of lines ratio good.
- wglb 17y agoI wonder. If it were only limited to the ratio of time required to type it, maybe. But I think during the writing of the program, you type the code, review the code, look at some other code, come back to that code, so you are writing/editing/modifying a particular piece of code multiple times. I have a superstition that there is an element of polynomial effect on the size of the resulting program on the time to get it working or to parse code written by another person.
- rgoddard 17y agoFor me, I have found that a more concise language is easier to think in and write in. I recently worked on an application that was implemented both on the web using mostly javascript and as a desktop application in VB.Net. One of the more complicated features I waited to implement in the web version, just because I found it rather difficult to think of the problem in VB. The javascript code was just easier to write and think in, and once implemented I could translate it to VB. Although I do not know if there is a limit to the benefits of moving to a smaller language. Also, this is just my personal experience and I do not know how much it generalizes to other people.
- req2 17y agoIt's not in writing 40 lines that something like "blub" hurts, it's in reading it afterward. As long as you don't end up in Perl one liners, shorter code will tend to better highlight the relevant content (e.g., there are four keys that perform one of four things).
- richcollins 17y agoCode generation isn't as powerful as late binding. Lisps would be more interesting if you could easily manipulate environments, and set the environment that functions are evaluated in. In this regard, Arc isn't as agile as some OO languages (Io for instance).
- wglb 17y agoI am curious what you mean about "easily manipulate environments" for the functions to be evaluated in.
- smikhanov 17y agoProbably, something similar to JavaScript's call() and apply() is meant here. Though classical Lisps all have funcall and apply (not sure about Arc).
- richcollins 17y agocall and apply only let you change the meaning of the this pointer in Javascript. You can't change the meaning of other bound variables. In Io, you can take a Block and set the scope: makeOriginalScope := block(name := "originalScope"; block(writeln(name))) block(name := "newScope"; makeOriginalScope call setScope(thisContext) call) call //newScope
- stcredzero 17y agoDoes this mean that you can change the meanings of your language's "words" for specific "contexts?" (Context meaning the semantic thing, not a stack frame, though that could be the implementation.)
- richcollins 17y agoYes. The meaning of symbols within a closure can't change after creation. They are always bound to the same variable. In Io, the meanings of symbols are determined when the block is activated.
- vlisivka 17y agoOriginal blub code should look like that: frame.addKeyListener(new KeyListener() { public void keyTyped(KeyEvent event) { switch (event.getKeyChar()) { case 'j': drop(); break; case 'h': move(-1); break; case 'k': move(1); break; case 'u': rotate(); break; } } public void keyPressed(KeyEvent event) { } public void keyReleased(KeyEvent event) { } }); About Arc code: (on-key-press frame 'u (rotate-shape) 'j (drop-shape) 'h (move-shape -1) 'k (move-shape 1)) Is this code ADDS NEW key event handler OR OVERRIDES old one? When it is invoked - when key is PRESSED or when key is TYPED?
- illumen 17y agoah, events as function calls. How so terribly 50's. here's a way where events are objects... rather than an invocation. Much more flexible. a python + pygame example... cu, key_handlers= dict(u=rotate, j=drop, h=lambda : move(-1), k=lambda : move(-1)) buttons = {1:'u', 2:'j', 3:'h', 4:'k'} for e in pygame.event.get(): if e.type == KEYDOWN: key_handlers[e.key]() elif e.type == JOYBUTTONDOWN: key_handlers[buttons[e.button]]() elif e.type in [QUIT, MOUSEBUTTONDOWN, HTTPD]: quit()
- stcredzero 17y agoThe grandparent code is much easier to understand.
- illumen 17y agoThe claim is Arc is agile and short... The Arc one has too many ()() all over the place. The arc one is also less powerful, because it uses different function invocations for different types of events. It's also likely more people will understand the python+pygame version. More people do currently understand the python version... hardly anyone uses Arc. You need to understand non-common concepts. You also need to understand how to create functions - rather than just call functions. Does that Arc one mean when the key down happens, or when a key up happens? Or maybe it means in between the key press and key down. Also, when will that code be called? It's magic. Will it be called from a separate thread, or some other Magic time... before or after the screen is to be updated? What else is going on at that time in the program? With the Arc version you have no idea... it's not explicit. Also Arc doesn't have first class events. It could have yes, but it doesn't. ps. the python code above was mangled by the buggy Arc program running this forum. Here is the code redone for simplicity without the extra shortness and power expressed in the other version. . for e in pygame.event.get(): if e.type == KEYDOWN: if e.unicode == 'u': shape.rotate() elif e.unicode == 'j': shape.drop() elif e.unicode == 'h': shape.move(-1) elif e.unicode == 'k': shape.move(1) Or the declarative python version: . dict( u=rotate , j=drop , h=lambda:move(-1) , k=lambda:move(-1))
- moe 17y agoI like this PG quote from slide 24 a lot: "One way to design a language is to just write down the program you'd like to be able to write, regardless of whether there is a compiler that can translate it or hardware that can run it." Test driven really works, even for language development.
- illumen 17y agoCan't do much without batteries.
- silentbicycle 17y agoI think it's impossible to have any kind of meaningful conversation about language design when one side is just writing off everything they don't like as "blub". It's incredibly condescending, no better than people reflexively writing off Lisp users as "lisp weenies".
- andreyf 17y agoWould it be as offensive to call the extra repetition that is inherent in some languages as "blub code", and languages like Arc trying to get rid of the blub(ber) in code?
- silentbicycle 17y agoI'd lean toward avoiding "blub" entirely; it sounds like you're implying their code (and brain) is full of mush. You're probably making a face like a fish blowing bubbles while you say it. Be civil! As novel as this may seem, most people who regularly program in languages other than Lisp also consider excessively verbose code to be a bad thing. (Hence the interest in refactoring.) If you're dealing with someone who just started programming a few months ago, they don't have enough experience to know why it's problematic, but then, they probably need someone to be patient and helpful, rather than smug. You can say, "There are some things that are inherently hard to express in some languages that come naturally in others, and until you have experience with a couple different styles of languages, you'll only really know techniques used in your main language. Learning new languages adds new techniques to your problem solving toolkit. It takes a while, but it'll make you a much better programmer in the long run.", and it doesn't make you sound like you're sneering inside. If you want to make the point that the way their language's object framework is designed makes any nontrivial program in it have a bunch of repetitive boilerplate, say that. Name-calling makes people defensive, not likely to consider new ideas.
- ken 17y agoI can't tell if you're trying to be funny or not. If we want to make a point about how a language is better at letting us build useful abstractions, we have to spell out exactly what we mean by that every time, even though somebody has invented a word that macroexpands to exactly that?
- Tritis 17y agoAnything Arc does better than Clojure that would be enough to offset the benefit of running on the JVM and full java interop?
- jimbokun 17y agoA Clojure slogan could be "The Java De-Blubber!"
- MaysonL 17y agoDid you notice the slide (#48) pointing to the Java implementation of Arc? I'm not sure how full the interop is yet, but it's a start. http://github.com/conanite/rainbow/tree/master http://github.com/conanite/rainbow/tree/master
- sharkbrainguy 17y agoit's built on plt-scheme so Tail Calls are optimised
- loch_ness_350 17y agoAs much as it annoys me to be continually banned for minor transgressions (time_management, banned_man, et al) when 99% of this forum considered me a great poster, I have a lot of respect for Paul Graham, and I think Arc is a great language. I use Clojure, because I'm at a 6-person startup that can't afford (yet!) to write its own libraries for certain cutting-edge functionalities available in the Java world, and the JVM provides a lot of benefits that are useful to us. But I think it's a tough call which of these competing new Lisps is a better language, and I'm glad they both exist because I think they have a lot to learn from each other.
- 10ren 17y agoSome other points of view here: http://www.reddit.com/r/programming/comments/8nuhn/my_language_is_smaller_than_yours_arc/ http://www.reddit.com/r/programming/comments/8nuhn/my_langua...
- psranga 17y agoA lot of the stuff presented here is mainstream practice in Tcl (e.g., new constructs, dbg evaluation). Tcl is seriously underappreciated language. In my programming whenever I see myself writing blubber (I like that word), I just factor it out into a separate procedure and give it a descriptive name. So when I'm reading the code of the calling routine, I rarely see blubber; it's contained in simple routines that are easy to read/verify. Most of the examples here amount to thoughtful library development. With a good library, C++ and macro processor can also many of these things. Here's a version of aif that works for most cases (I'm not claiming that C has the expressive power of Lisp): #define aif(expr, val, code...) \ { if ((expr) != (val)) { \ code ; \ } \ } IMHO, this is good enough for blubber reduction.
- dreish 17y agoThat's not aif at all. In fact, you can't even do it for "most cases" in C because you don't know what type expr will evaluate to, but if we could cheat and assume it will be an int: #define aif(expr, code) \ { \ int it = (expr); \ if (it) \ { \ code; \ } \ } But this is still not close because in a Lisp, if is an expression that returns a value. We can't use the ternary operator because then there's no place to declare the "it" variable. You can't have an expression that declares a variable local to that expression in C no matter how hard you try. And the above lacks the "do {} while (0)" weirdness needed to make a cpp macro behave syntactically roughly like a function.
- psranga 17y agoI agree. My bad. I appreciate the clarificaiton.
- st3fan 17y agoThis presentation could have been about Clojure instead. Just s/Arc/Clojure/
- stevedekorte 17y agoFrom the slides, it looks like Arc dumps lots of short words in to one giant global namespace where they can easily collide with local names. Is this correct? For example, it looks like Arc uses the "t" as a global true value. Is it really safe to assume "t" wouldn't be accidentally used as a local variable?
- randallsquared 17y agoWell, T has been the true value in Common Lisp, at least, and I don't remember it ever causing me a problem. Of course, in CL, you can shadow it in your own namespace, and that hasn't been possible in Arc without writing a namespace library first. :)