Slashdot Mirror


Why Java Won't Have Macros

bugbear writes "Carlos Perez has just posted a page that quotes Sun Java 'theologist' Gilad Bracha about why there is no plan to add macros (in the Lisp sense) to Java."

33 of 140 comments (clear)

  1. in the Lisp sense? by Tumbleweed · · Score: 4, Funny

    No macroth? Thath too bad. ;)

  2. OOP by sporty · · Score: 3, Informative

    Just to clarify further why macro's are bad.

    The problem with macros, is they sorta defeat Java's OOP. Think of it. Defining a symbol, just to be replaced in thousands of other places where it's written, tied only to the global space.

    Sounds awfully like a procedure/function to me.

    If you tied macros to objects, they'd just be inline methods. So there really is no point.

    --

    -
    ping -f 255.255.255.255 # if only

    1. Re:OOP by pauljlucas · · Score: 4, Insightful
      The problem with macros, is they sorta defeat Java's OOP
      Macros have nothing to do with programming methodology (OOP, procedural, functional, etc).
      Defining a symbol, just to be replaced in thousands of other places where it's written, tied only to the global space.
      Yes? So? What things are named or what text is substituted before the compiler looks at it has nothing to do with OOP.
      Sounds awfully like a procedure/function to me.
      Macros are text substitution or syntax tree manipulation alone. Macros are not called, so why you think they have anything to with procedures or functions?
      --
      If you reply, do so only to what I explicitly wrote. If I didn't write it, don't assume or infer it.
    2. Re:OOP by Dr.+Photo · · Score: 4, Informative

      The macros the article is talking about are Lisp-style macros.

      These are not your "shoot self in foot" C macros (i.e. replace text x with text y), but a very powerful and expressive way to have the entire language at your disposal at compile time.

      If you've seen the neat tricks you can do with C++ templates (template metaprogramming, etc), you might have an idea of what real macros would be like, when severely watered-down.

      Lisp macros make things like Generic programming and OOP very simple to add to a language, as well as almost any other conceivable programming construct.

      For instance, with proper macros in Java, you wouldn't ask, "When will templates be added to Java?"; you could add them yourself.

    3. Re:OOP by sporty · · Score: 2, Interesting
      I think you ran into the same problem that a lot of Java purists may have. They want java to look like java and not have a language inside the code which does neat syntatical stuff. Not that it's bad intrinsically, after all what is? :)

      Lemme also take a segment from what your link has.



      (define-syntax (while stx)
      (syntax-case stx ()
      [(_ test body)
      #'(letrec ((loop (lambda () (if test (begin body (loop))))))
      (loop))]
      [else (raise-syntax-error 'while "Illegal syntax in while loop" stx)]))

      Notice in that code fragment how obvious it is what's happening, even if you don't know Scheme



      It's not obvious to us all. I'm slightly confused on what exactly is happening. It looks recusive... though it prolly isn't.
      --

      -
      ping -f 255.255.255.255 # if only

    4. Re:OOP by reynaert · · Score: 2, Insightful
      Macros are text substitution or syntax tree manipulation alone. Macros are not called, so why you think they have anything to with procedures or functions?

      Well, that depends on the language. In Common Lisp and most other Lisp dialects (not Scheme tough), macro's are normal functions that are run at compile-time instead of at run-time. They can do everything normal functions can do, such as calling other functions, doing I/O, etc..

    5. Re:OOP by Dr.+Photo · · Score: 3, Informative
      It's not obvious to us all. I'm slightly confused on what exactly is happening. It looks recusive... though it prolly isn't.

      Actually, you're correct. It defines a syntax for a while loop by creating a function that does (in pseudocode):
      def loop() {
      if(test) {
      do_stuff_in_loop_body();
      loop();
      }
      }
      Note that this kind of recursion is a common way to express iteration in Scheme/Lisp, as it is "tail-recursive" (i.e., doesn't require going back to the calling function once the next loop() is called), and is optimized by the interpreter/compiler to be generally as efficient as iteration.
    6. Re:OOP by sporty · · Score: 2, Insightful

      But you see, that uncertainty, that new language I need to read, is what java develoeprs shouldn't have to deal with. It's like Java and SQL. EJB solves a lot of that, "I need to know SQL to get stuff from the DB." The exception is when you have to define finder functions in your configuration. Point is, it doesn't change how java looks. No syntax changes.

      That's prolly what java doesn't want. Syntax changes done by something like macros, or from what you've pointed out.

      --

      -
      ping -f 255.255.255.255 # if only

    7. Re:OOP by sporty · · Score: 2, Interesting

      You are absolutely right. You odnt' have to stop using OO. Point is, you'll start mixing theologies. You'll have objects calling a mess of procedures.

      But back to the macro bit. You are right, anything can be made to create a mess... but lemme attack it from the other end. With OOP, an object has its methods on what it can do. If a method calls another objects methods, it's ok. It's straight forward etc... since each object effectively becomes a mini library.

      With procedural programming, which what macros are kinda like, code written in place with no object ties, though I know it is inline text replacements, you can have macros call other macros, call objects, call other macros to a very large mess.

      Macros do one thing really well.. it allows you to write clean looking code.. in an inline way. But it's easier to write spaghetti code, everything calling everything else with procedural programming. You can effectively create this mess with macro programming.

      --

      -
      ping -f 255.255.255.255 # if only

    8. Re:OOP by Tablizer · · Score: 2, Insightful

      The problem with macros, is they sorta defeat Java's OOP.......Sounds awfully like a procedure/function to me.

      Sounds like you are bashing procedural. There is no evidence that OOP is objectively better than procedural. For every "fault" you can find in procedural, I bet I can either find a better procedural way to do it, or find flaws with the OO approach also that you either never thought of, or ignored out of habit.

      (PS. If you tag this message "flaimbait", then please tag the parent also. Them'r the one who started the paradigm war. As far as macros being good, I am on the fence on that one.)

  3. Interesting point. by alyosha1 · · Score: 5, Interesting
    The single best measure of whether a programming language is worth using is: how well does it support communities.
    This point doesn't seem to get raised very often when comparing the relative merits of language A against language B. It's easy to forget that while a language is a tool for communicating with a computer, it is also (and arguably more importantly) a tool for communicating with other programmers.

    Which is why Python is rapidly becoming my favourite language. I find other people's python code far easier to understand than stuff written in other languages. This despite the fact that I've only been hacking python for a few months, and I've been using C++ and other languages daily for several years.

    I feel that there's scope for yet another 'methodology', alongside OO and XP and all that - it might be called 'code as conversation', whereby the quality of a piece of code is judged by how readily it communicates intent to other programmers.
    1. Re:Interesting point. by Fnkmaster · · Score: 2, Insightful
      One of Java's biggest strengths is the fact that you can generally pick up and read somebody else's Java code, segment by segment, without having to grok the uber-design of the project. This code readability factor is huge. Another poster mentioned LFSP vs. LFM (languages for smart people vs. languages for the masses) - this division I think is real (though I would trash the loaded descriptors and call them "syntactically powerful languages" vs. "syntactically constrained languages").


      Java is clearly a syntactically constrained language. As a programmer seeking to build a powerful library or problem solving toolkit for a complex application domain, this can be annoying. And several others have pointed out that this seems to keep resulting in people creating meta-languages (XML-based or otherwise), code-generators and the like for complex Java projects because they are needed to solve certain kinds of problems in an efficient manner. This is certainly true, and such systems can become rather ungrokable fairly rapidly. However, you can generally isolate such complexity from the hordes of mediocre developers who are there to pound out mediocre, simple code.


      With LISP, or even C/C++, the power is there all the time. Programmers will inevitably try to use the tools they learned about in school and _will_ shoot themselves, their development projects, and their managers in the foot. Java creates a hierarchical system of complexity - most Java code is universally readable, and if there is a need to learn special metalanguages (EJB descriptors for example), they are usually highly constrained XML dialects, separated out from the rest of the Java code. Sure, there's an XML parser and code generator that only one guy really understands and can maintain, but if that lets the rest of the development team pound away on their mediocre code in standard, vanilla Java, and edit some simple XML documents, then it makes software development more efficient.


      When you are managing mediocre people, you can appreciate the benefits of having them work in a language that prevents them from doing too much damage. Development is more predictable, bugs tend to be more apparent and less insidious, even though it's not always the most powerful or most efficient language for every problem domain. Of course, there are a lot of domains where you'd be crazy to try to use Java. And when you tackle those problems, you need to hire better developers who can handle the power of LFSPs (or at least languages with more foot-shooting power).


      And I consider Python to be comparable to Java in terms of readability. It is similarly somewhat syntactically constrained, with relatively few obvious mechanisms to accomplish a task, as opposed to way too many mechanisms to accomplish a task - and I love the forced code indentation as well (it forces consistency of style, another readability barrier). Where Python loses out is its far less comprehensive, standardized or well documented API, though I'm sure Jython has come quite a ways since I last looked at it (Python code + Java API - potentially a very good tool for scripting use in large Java projects). However, for larger software projects involving a large number of modules and many developers, a weakly typed language fails utterly - you need strict enforcement of method contracts and object typing that you get from a strictly typed language. This goes a long way to improving code readability and modularity for larger projects, and lets you catch many simple errors during compilation instead of having to rely on yourself to catch them all, or waiting until runtime to find problems ("oh, of course, I need to pass method foo an Orange object and two strings, not an Orange, a Grape and an integer").

  4. Re:useless by Tumbleweed · · Score: 4, Funny

    > if u want the extra performance boost

    Maybe you wouldn't find macros so useless if you created some keyboard macros to replace ' u ' with ' you '.

    Just a thought.

  5. Re:useless by reynaert · · Score: 4, Informative

    No, in Lisp macro's aren't used for inline functions , but for syntax extensions. For a demonstration of what real macros can do, look at The Swine Before Perl. That presentation shows how easy it is to implement special syntax for automatons in Scheme, and how natural & simple the result looks.

  6. Sigh.. by DrunkBastard · · Score: 5, Funny

    One less language to be used in obfuscated code contests. Where's the fun without macros and overloading? sigh....

  7. Re:useless by reynaert · · Score: 2, Interesting

    I think the readability argument is bogus: you could say exactly the same about every form of abstraction (functions, classes, ...). Of course, if you have a brain dead macro system as in C and you do things like:
    #define FOO bar + 2 *
    (seen in flex source), you have a problem. With a decent macro system (such as Common Lisp, Scheme, and Dylan have), you avoid these kind of problems. (btw, Dylan has an ordinary, infix syntax, so having lots of parentheses is not a requirement...)

  8. Strange, I've been arguing about this all day ... by torpor · · Score: 4, Interesting

    ... and losing badly.

    Okay, C programmers, tell me why these 4 macros are bad:

    #define is ==
    #define and &&
    #define or ||
    #define until(a) while(!(a))

    Tell why they're good if you think they're good, but I'm only interested in the bad argument (having lost it all day). :)

    --
    ; -- the corruption of government starts with its secrets. a truly free people keep no secrets. --
  9. Re:Strange, I've been arguing about this all day . by reynaert · · Score: 4, Interesting

    They're bad because they don't extend the C syntax, they just change it. Good macros extend the syntax, but keep the new syntax in same style as the original language. If you want to know to what your four macro's lead, look at the famous Bourne shell source code. A few simple definitions like yours in mac.h result in the horror of xec.c and cmd.c.

  10. If this is what Jabba does, then Jabba will lose. by ArmorFiend · · Score: 4, Informative
    The crux of his argument is that user defined macros make code unreadable. If users are able to create their own macro constructs, they'll be "making their programs unreadable for everyone else". This is pure hogwash from someone that's probably never used hairy-chested lisp macros seriously. I'll demonstrate to you the hogwashishness in two phases.

    Flash-back to 1969 when the same arguments were put forward by assembly programmers against named functions:

    User defined functions make code unreadable. If users are able to create their own functions, they'll be "making their programs unreadable for everyone else".
    History has show that user defined functions are good. People are finally realizing that lisp macros are perhaps an equally important good. By taking this position, Jabba is positioning itself on the losing side of history.

    Seriously, what's easier to read:

    // macro-less call
    {
    window.context().glxMakeContextCurrent();
    float[4] color = window.fgColor();
    glColor(color);
    glPushMatrix() ;
    glIdent();
    glAlphaBlend( GL_FALSE );
    ...non-boiler-plate-code...
    glAlphaBlend( GL_TRUE );
    glPopMatrix();
    }
    OR
    // macro call
    withGLDrawing (color) {
    ...non-boiler-plate-code...
    }
    If you look at it in terms of lines of code, in terms of error-prone-ness, in terms of high-level versus low-level, in terms of maintainability, ONLY AN IDIOT WOULD CHOOSE AGAINST MACROS.

    Okay, sorry for being ornery, but mod this scruffy post up!

  11. Re:If this is what Jabba does, then Jabba will los by reynaert · · Score: 3, Insightful

    You're completely right of course. But as many people are complaining macro's don't fit in Java's everything-is-part-of-a-class philosophy, I'll just point out you can easily put macro's in classes and use them like this (assuming you have an OpenGL class):

    OpenGL.withDrawing (color) {
    ...non-boiler-plate-code...
    }
  12. Perl by (trb001) · · Score: 4, Insightful

    given this statement

    The real point is that LFSPs (Language for Smart People) have a much greater support for abstraction, and in particular for defining your own abstractions, than LFMs (Language for the Masses). ...has anyone declared Perl *the* LFSP? I can't think of a more abstract and unreadable language off the top of my head (Cobol doesn't count just because the younger generation has never used it).

    --trb

  13. Re:Strange, I've been arguing about this all day . by FroMan · · Score: 4, Interesting

    Programming languages are similar to spoken/written language, they are meant to convey an idea. In programming the ideas are instructions to the computer and to someone maintaining the code. For each language there are pedantic ways of doing things, usually from tradition or common ideas.

    In C when you are writing and infinite loop for a server, the standard way to do it is

    for (;;) {
    if ((acceptfd = accept(...)) < 0) { /* handle errors here */
    }

    if ((pid = fork()) < 0) { /* handle errors here */
    }

    if (pid == 0) { /* parent */
    } else { /* child */
    }
    }

    There are two very common C practices used in this. The first is the for (;;) {}. This is the standard way to do it because there is no comparison ever used within the loop, where a while (1) {} would seem to do the same thing it does have a comparison. Well, now it wouldn't matter since the compiler would optimize the loop anyways since the '1' is a constant, older compilers or non-optimizing compilers would not catch that though.

    The second practice is the if ((x = f()) < 0) {}. This arises more out of tradition. It gets the return value of a system call and allows the error handling to be done immediately. It also helps keep the indenting level from running away.

    Ammusingly enough in Java with JCSC I find that it gives warnings saying it is bad style. I would guess that it would prefer

    try {
    int acceptfd = accept(); // non error condition here
    } catch (Exception e) { // handle accept error here
    } finally { // no matter error or not here
    }

    From a C background I find this abhorrent. Look at the level of indentation required! Evil!

    Well, what does that have to do with #define or ||? Tradition. C programmers are used to seeing "||" as an "or". There is no keyword "until". If a C developer is hired new into the place he will have to learn the idiosyncracies that this place uses.

    Specific arguments against using macros to extend the language are that you are in effect adding keywords to the language. In effect "or", "and", "is" and "until" are now keywords in C. Since these are not part of the language normally, any code that uses any of those as a variable will now have issues.

    Well, who would use "or", "and", "is" as a variable name? Well, look at the linux kernel code and you will find that "new" is used occasionally, which causes the kernel to not be able to be compiled with a C++ compiler. I would also argue that "or" could easily mean outputReport and "is" quite often means inputStream to me.

    By using this "or", "and", "is" nonsense you are also leaving out the possiblity of using similar ideas for bit fields. You could use "xor", but you would need a "bor" for bitwise or'ing of a field.

    Basically what I see by using the macros here is that you are limiting yourself to a number of poor programming practices. When you use these you will be confusing real programmers and potentially inserting errors into the code. In C "||" is well defined and any C programmer is able to understand it. "or" on the other hand is ambigious to C programmers since it is not part of the programming language.

    --
    Norris/Palin 2012
    Fact: We deserve leaders who can kick your ass and field dress your carcass.
  14. Re:useless by Elwood+P+Dowd · · Score: 5, Funny

    >> if u want the extra performance boost

    >Maybe you wouldn't find macros so useless if you created some keyboard macros to replace ' u ' with ' you '.
    >
    >Just a thought.

    Maybe yoyou woyouldn't find macros so youseless if yoyou created some keyboard macros to replace 'you' with 'yoyou'.

    Jyoust a thoyought.

    --

    There are no trails. There are no trees out here.
  15. Higher-order functions mostly make macros obsolete by Tom7 · · Score: 2, Insightful

    If you have higher-order anonymous functions in your language, than it's easy to do this kind of thing by turning the binding inside-out and making it an argument to the rest of the code. In general macros that bind variables or have effect are trouble, because, for one thing, the scope of declarations is "open."

    I used to be a crazy cowboy C programmer, and I loved macros more than anything. But seriously, functions go a long way, as long as they are syntactically brief (anonymous) and semantically powerful (nestable, higher-order). I program mostly in SML these days, and hardly ever wish I had macros.

  16. Java needs Macros, Badly by __past__ · · Score: 4, Insightful
    Lisp-style macros are, in a sense, all about syntactic sugar. They let you write stuff easily and predicably that would be possible, but inconvenient by hand, to the extent that it becomes natural to implement domain-specific languages with them.

    Java, and about every non-Lisp language, lacks syntactic extensibility. Yet, Java programmers obviously consider Java syntax to be not usable for a lot of everyday tasks - hence the ever-growing number of special mini-languages around Java, like Ant-XML, XDoclets, JXPath, to a degree even XSLT.

    Of course it is possible to implement such DSLs in Java, but you typically end up writing an interpreter, and that usually means that, if you want to use the DSL in your program (say, evaluating expressions built at runtime), you end up manipulating strings and feeding them to a huge, opaque interpreter machinery - which is error prone and the hell to debug. And, by the way, one of the things people often call one of the biggest problems of macros, when they only know C-style ones.

    Basically, much of what macros allow you to do is already done in the Java world, just without the language supporting it, and hence in slow, buggy and hard-to-debug, often ill-specified ways.

    1. Re:Java needs Macros, Badly by Anonymous Coward · · Score: 2, Interesting

      Syntactic sugar is generally harmful.

      Why?

      Unless you are the only one writing the code you read and the only one reading the code you write, the "sugar" is poison to long term readability and maintenance.

      Trying to get junior programmers just to understand all the built-in standard bits of a simple language like Java is bad enough. C++ is murderous in this regard.

      In this same regard, I like some aspects of C++ that Java left out -- for my own personal use, but I'd never wish them on a project at a company I work for.

  17. Re:useless by Procyon101 · · Score: 3, Informative

    I politely disagree. Although I have never actually used goto in a program, I can concieve of a severely nested loop with an exit condition that would have to be propagated all the way out of a the loop. This could prove overly complex, having to check for the condition in every loop (perhapse this is a 16 dimentional data structure and we are doing a search and we happen to find the value early by luck). Throwing an exception is an option, but since this might not be an "exceptional" condition, some people might be philosophically opposed to it. In this (extremely rare) case, goto has a very good organization purpose.

  18. Great... by MeanMF · · Score: 2, Insightful

    Programming languages are cultural artifacts, and their success (i.e., widespread adoption) is critically dependent on cultural factors as well as technical ones.

    So the idea is to gain wider adoption by not implementing powerful features that might make code harder to understand. That should sound pretty familar to people who use VB... Not that there's anything wrong with that.

  19. Gotos by r6144 · · Score: 2, Informative
    In some cases GOTOs are very useful, especially in languages like C for error recovery. Look at the many "goto error"s in Linux Kernel code, they cannot look as good in any other C way. Of course in java you don't need to manually destruct things so often, so gotos are not that useful. Multi-level exits are also an important use for GOTO, and IMHO block labels are similar but less readable.

    Also, some programs that does loops in irregular ways (such as non-recursive searching programs that backtracks) can be rewritten in a way that is much more readable IMHO. Alas, it is still as hard to make sure such code is correct, since you still have to follow every possible execution path, so it doesn't make the writer's life better.

  20. Re:Strange, I've been arguing about this all day . by spongman · · Score: 2, Insightful
    For the same reason the following:

    typedef int DWORD
    typedef char* LPSTR
    (yes, burn in hell Microsoft)
    are bad

    The reason those typedefs are good is that they insulate the programmer from the compiler that they're using.

    Quickly now, can you tell me if 'char' is signed or unsigned by default on your C++ compiler? Or how long is an 'int'?

    It's a simple matter to change those definitions in a single place, but if you change compiler you may have to refactor a whole lot of your code to keep it compatible. Using the typedefs you will always know that a DWORD is an unsigned 4-byte value and a LPSTR is a pointer to signed bytes.

  21. Re:useless by j7953 · · Score: 2, Insightful
    Although I have never actually used goto in a program, I can concieve of a severely nested loop with an exit condition that would have to be propagated all the way out of a the loop.

    Java has labeled statements, so you can put a label on the outermost loop statement and then simply write "break label;" when you have to exit all the loops.

    outermost: for (...) {
    //lots of nested for statements here
    if (something) {
    break outermost;
    }
    }
    --
    Sig (appended to the end of comments I post, 54 chars)
  22. Macros are not macros! by mrami · · Score: 3, Informative
    Just so everyone understands, in Lisp, macros are not text replacement systems. In Lisp, macros are functions that take a set of syntactic forms and return a new syntactic form to the compiler. You're not breaking any OOP principles here, any more than ArrayList breaks them by always using Objects.

    So, for example you could write a macro that takes a variable, a list, and a statement and returns a for-loop that iterates over the variable, and call the macro, say, 'foreach'. Or you could write a macro that takes a boolean expression on a set of classes and return a statement block to do some JDBC calls and create a bunch of objects that represent the join of that expression. Or... (substitute here anyting you do on a regular basis that can't be made into a method).

  23. Re:Macro's are for the lazy by Tablizer · · Score: 2, Insightful

    While laziness can be a virtue for a good programmer, the truth is that Macros lead down that ugly slippery slope that ends in completely unreadable code. It may work great for a few programmers, however once you start working on large projects with many people coming and going you end up with a freaking mess.

    Just about any tool/feature can be turned into a mess maker. There is no language that jabs stupid programmers in the eye when they get stupid (other than maybe crashing or buggin' out and being hard to debug).

    However, I will agree that some features can be downright ugly in the wrong hands. I would rather debug sloppy Pascal than sloppy Perl, for example. But, that might not necessarily be my same choice if it is my own code that I have to work with.