Say, if I have a Lisp program, which uses (eval 'sym)
and looks it up in its symbol-table does it actually perform better than something like aClass.getField("sym", anInstance)
in "static" languages?
views:
151answers:
3It depends on the implementation of a language.
There is absolutely no reason why e.g. the aClass.getField("sym", anInstance) should not no exactly the same as an eval does.
On the other hand even WITHIN actual implementations the speed is hugely different. E.g. in .Net there are slow reflection methods and fast ones (often 100 times and more faster). And which one you need depends for the most part on what you actually want to do with the method. Do you want to just read a value? Change a value? Is security relevant?
The question is not well posed, in part because the two approaches are not mutually exclusive.
Just as an example, Common Lisp provides EVAL
.
Common Lisp also provides a number of reflective capabilities, allowing you to see what symbols are in a package, find values of (global) variables by name, construct instances of classes by name, find or set values of slots in classes, or call functions based on their name. With the widely implemented (though non-ANSI standard) CLOS Meta-Object Protocol, you can find out even more about classes and generic functions based on their names.
Of course, the problem of comparing the performance of languages instead of implementations remains. Naturally Common Lisp that has been compiled to native code will perform quite differently than Common Lisp that is being interpreted, and most CL implementations allow you to mix compiled and interpreted code (though a few only provide compilers).
In general (modulo implementation issues like bytecode vs native code or code generation quality), languages with metalinguistic abstraction provide more power to create programs that outperform programs that can be created in comparable timeframe with language that lacks such abstractions. The case is that when you write an implementation for your own language, you have more information to make much more powerful optimizations than compiler for base language can do. There are numerous examples of this in practice.
Also, you seem to mix together the reflection (being a particular case of 'open implementation') and metalinguistic abstraction. Metalinguistic abstraction is about building new languages on top of base languages and reflection (or 'open implementation') is about exposing program's internals to the program itself.
In your particular example (of course, module implementation issues like bytecode vs native code or code generation quality), (eval 'sym)
is probably faster. The reason is that 'sum
is a symbol object and not a string. Evaluating a symbol means taking its value cell. So eval has to do only several things:
- Dispatch on an object type (in this case - a symbol) (e.g., by using a value tag to go through jump table)
- Extract symbol's value (by dereferencing a symbol structure)
But Java example has more things to do:
- Find a field given its name. This requires e.g. calculating a hash of a string and using hashtable
- Extract the field's value (by dereferencing instance pointer at an offset specific to field)
- Box the value (if it's not a reference)
The particulary expensive part is calculating the hash and going through hashtable.