5 ms·
> Smalltalk doesn’t need macros because it has classes instead. I'm not sure this is true. Surely any programming language that lacks macros would be more powe
by big_spammer 9y ago
> Smalltalk doesn’t need macros because it has classes instead.
I'm not sure this is true. Surely any programming language that lacks macros would be more powerful with them.
- aaron-lebo 9y agoIt might be more accurate to say: > Smalltalk doesn’t need macros because it has classes, powerful introspection capabilities, and simple expressive syntax (especially blocks) instead. There's a debate to be had if compile-time macros are superior to passing blocks as arguments. It also is easy to make your language parser extensible or easy to modify without having traditional lisp macros. Metalua does something like this.
- gnaritas 9y agoYea, that's a weird statement, however a better one is that Smalltalk doesn't need macros because it has a clean syntax for lambas that remove a common use for macros, hiding boilerplate use of Lisp's lambda. Beyond that, Smalltalk isn't file based, you don't edit some version of the code that gets compiled (and macro expanded) into some runtime version of the code you can only see through introspection; rather in Smalltalk you're actually editing the runtime version in a running image. Macros simply wouldn't fit into Smalltalk in any meaningful way and Smalltalk's syntax is pretty much already ideal for building DSL's without the need to clean it up with macros. What makes both Lisp and Smalltalk interesting is that there's no difference between language and library; the constructs you create yourself are on equal footing with the ones most consider built in. Macros let you build special forms to control evaluation semantics, Smalltalk simply uses blocks [ ] to delay evaluation, and both languages are their libraries. Lisp has functions/macros, if/cond, etc; Smalltalk has objects used in a way you simply do not see in other object oriented langauges. Smalltalk has no if statement, no while statement, no reserved words beyond true, false, nil, self, super, and thisContext, everything else is library including all control flow constructs which are implemented with objects/classes/inhertance, and polymorphism. They are both "pure" languages in a sense, and that pleases some people greatly. If you haven't programmed in Smalltalk, you really have no idea what object oriented actually means at a deep level. All of the popular so called OO languages are actually just procedural languages with hundreds of special keywords that have classes, but the languages themselves aren't build from classes and objects, they're procedural and defined by the compiler writer as special forms you cannot create yourself. Having objects, and being truly object oriented all the way down, are drastically different things.
- deleted 9y ago[deleted]
- teddyh 9y ago> Smalltalk isn't file based, you don't edit some version of the code that gets compiled (and macro expanded) […] Macros simply wouldn't fit into Smalltalk in any meaningful way […] You speak as if “macros” means “macros as implemented in the C preprocessor”. Lisp macros, as I understand it, operate on the parsed syntax tree, not on the file text level, and are expanded at runtime, not compile time.
- aaron-lebo 9y agoThe key to understanding macros is to be quite clear about the distinction between the code that generates code (macros) and the code that eventually makes up the program (everything else). When you write macros, you're writing programs that will be used by the compiler to generate the code that will then be compiled. Only after all the macros have been fully expanded and the resulting code compiled can the program actually be run. The time when macros run is called macro expansion time; this is distinct from runtime, when regular code, including the code generated by macros, runs. http://www.gigamonkeys.com/book/macros-defining-your-own.html http://www.gigamonkeys.com/book/macros-defining-your-own.htm...
- lispm 9y agoThis is the view of a compiled execution. Lisp can also be interpreted from source as data. Then macro-expansion time is interleaved with execution time. Each use of a macro form may trigger a macro expansion. Remember, a Lisp interpreter interprets Lisp source as data. Not byte code. Unlike Python, Java, Smalltalk, ... which all have popular implementations which compile to byte code and execute that byte code in a byte code interpreter, aka virtual machine. Let's use a Lisp interpreter, here from LispWorks: We define a primitive MY-IF macro. It expands into a simple IF use. But the macro will also count the number of macro expansions. CL-USER 46 > (defparameter *myif-counter* 0) *MYIF-COUNTER* CL-USER 47 > (defmacro my-if (c a b) (incf *myif-counter*) `(if ,c ,a ,b)) MY-IF LispWorks can trace macros, too. CL-USER 48 > (trace my-if) (MY-IF) Now a simple function which uses our macro: CL-USER 49 > (defun fac (n) (my-if (= 1 n) 1 (* n (fac (1- n))))) FAC Now we use it and we will see the trace information for the macro use: you see the incoming form and the result form. CL-USER 50 > (fac 2) 0 MY-IF > ... >> COMPILER::FORM : (MY-IF (= 1 N) 1 (* N (FAC (1- N)))) >> COMPILER::ENVIRONMENT : #<Augmented Environment venv NIL fenv ((#:FUNCTOR-MARKER . #<COMPILER::FLET-INFO (# # # #)>)) benv NIL tenv NIL decl NIL> 0 MY-IF < ... << VALUE-0 : (IF (= 1 N) 1 (* N (FAC (1- N)))) 0 MY-IF > ... >> COMPILER::FORM : (MY-IF (= 1 N) 1 (* N (FAC (1- N)))) >> COMPILER::ENVIRONMENT : #<Augmented Environment venv (#<Venv 275415194600 N>) fenv ((#:SOURCE-LEVEL-ENVIRONMENT-MARKER . #<COMPILER::FLET-INFO (NIL . #)>) (#:FUNCTOR-MARKER . #<COMPILER::FLET-INFO (# # # #)>)) benv NIL tenv NIL decl NIL> 0 MY-IF < ... << VALUE-0 : (IF (= 1 N) 1 (* N (FAC (1- N)))) 0 MY-IF > ... >> COMPILER::FORM : (MY-IF (= 1 N) 1 (* N (FAC (1- N)))) >> COMPILER::ENVIRONMENT : #<Augmented Environment venv NIL fenv ((#:FUNCTOR-MARKER . #<COMPILER::FLET-INFO (# # # #)>)) benv NIL tenv NIL decl NIL> 0 MY-IF < ... << VALUE-0 : (IF (= 1 N) 1 (* N (FAC (1- N)))) 0 MY-IF > ... >> COMPILER::FORM : (MY-IF (= 1 N) 1 (* N (FAC (1- N)))) >> COMPILER::ENVIRONMENT : #<Augmented Environment venv (#<Venv 275416002360 N>) fenv ((#:SOURCE-LEVEL-ENVIRONMENT-MARKER . #<COMPILER::FLET-INFO (NIL . #)>) (#:FUNCTOR-MARKER . #<COMPILER::FLET-INFO (# # # #)>)) benv NIL tenv NIL decl NIL> 0 MY-IF < ... << VALUE-0 : (IF (= 1 N) 1 (* N (FAC (1- N)))) 2 Let's see how often our macro function has been used to expand code: CL-USER 51 > *myif-counter* 4