Continued (or refactored) from SetsAndPolymorphism eval(record.functionName) versus object.methodName() Eval Pros * Can easily use other record attributes with multiple languages and query tools. * Avoids having to build data-structures into code and/or mirror the database structures. Cons * Slower * May be security risk if database hacked. * No compile-time checking (not applicable to interpreters) * Exceedingly difficult to maintain ''- not very specific'' * Bug prone ''- not very specific'' * A nightmare to debug when something goes wrong ''Please avoid vague words like "difficult", "nightmare", etc. The don't provide usable info and risk triggering a FlameWar.''. Polymorphism Pros * Encourages building structures into code. ''Vague'' It's the inverse to the 2nd eval pro which is just as vague. ''See example below.'' ---- Which "eval", Lisp's? That's the only truly famous one. If you mean something else, its semantics need to be defined. ''The "evals" I am familiar with evaluate the expression as if it was in the code. The following would be functionally equivalent:'' x = a * b x = eval("a * b") A wider-purpose variation is "execute". It basically executes the given string as code. ---- '''Change Impact Example 1''' Suppose we have (sample) records in a RDBMS table with four columns: "id", "x", "y", and "func". "Func" is the expression (function name) to be evaluated. Or, you can think of it as a "strategy name". . ID X Y func . -- --- --- ------- . 4 2.0 8.1 "foo" . 5 3.0 9.9 "bar" . 7 4.5 5.6 "blah" . 8 3.3 7.2 "foo" If we get X and Y from the database, but use OO for dispatching, then we have to find some way to map the records to classes/methods. If we use eval, then we don't have to add any new code for record 8. For example, if we start out with 3 records, but then add record number 8 (id=8), '''in OO some way must be found to map record 8 to method/class "foo"'''. Eval appears to be more change-friendly for this scenario. The data record has to be added under both paradigms I would note, so does not count against the eval version. I don't see a direct polymorphic way out of this. ''The OO solution doesn't require polymorphism. Use a closure.'' It might be off-topic, but an example would be nice. ''An example of a closure? Here's one in Java:'' public class S''''''ampleRow { int id; double x; double y; Function aFunction; } public abstact class Function { abstract perform(S''''''ampleRow row); } ''When you find the row you're looking for, ask it's Function to perform on it ("aRow.aFunction.perform(aRow)"). Use anonymous inner classes to define the closures. And I take it back. This solution does require polymorphism (although I think other languages with closures don't.)'' "Perform" is Eval's close cousin. It would be like a library function "executeFunction(functionName)". It is not an OO-specific concept. ''You said you didn't see a "polymorphic way out of this", so I showed you one. "perform" is just an abstract method on an abstract class. It's nothing like eval. It's type checked, can be over ridden, etc. I'd much rather use a closure than execute whatever string I found in a text field and hope for the best.'' Fine. But closures are not an OO concept (depending the ever wavering definition of OO being used.) An OOP language that does not have closures nor dynamic execution flunks the no-code-change test then. OO by itself cannot solve it. (Maybe test it in Eiffel?) It has to borrow concepts outside of OO, and concepts very close to eval in nature for that matter. ''The example I gave is nothing like eval. I'm not compiling data into code at run time. I'm storing a reference to code in a data structure. There's an important difference. I'm unaware of any OO language that couldn't implement the solution above.'' [''Who is arguing for pure OO, abandoning all programming concepts outside of OO? That seems to be a StrawMan that you have erected, Top, and persist on knocking down repeatedly. That position (that we should use OO and only OO) is arrant foolishness in my opinion. Use whatever paradigm is appropriate. If closures come from OO, functional, relational, or the third moon of Jupiter I don't much care. I use the tools that are appropriate when they are appropriate.''] * Fine. And in some cases use Eval. '''This is what this topic is about: when Eval helps and when it doesn't'''. This scenario seem to be a case where Eval has at least one objective benefit: less change points. Polymorphism does not always stink and Eval does not always stink. It is just another small lesson in WhenToUseWhatParadigm (or technique). (By the way, I find your "strawman" comment a bit offensive.) Reflection pretty much lets one get at internal "schema" of Java's guts. It is almost (bad) TOP. ''What does reflection have to do with this? The example I gave doesn't use reflection.'' Maybe I am misinterpreting what the "perform" method above does. ''It's just a method. It does whatever its code says it will do. It's an abstract method in the Function class, so each specific Function will define what it does. It does not use reflection.'' I am not a Java expert. Could you please explain exactly what is happening there? The context seems to claim it is using closures. Thank You. ''It is a closure. Function contains an abstract method, perform(). Each S''''''ampleRow contains an instance of a concrete subtype of Function. Each concrete subtype of Function does one thing, defined in its perform() method. There's no reflection involved, no run-time compilation or evaluation going on. Something will find a S''''''ampleRow and ask it's "aFunction" member to perform(). It's all statically type checked and compiled beforehand. The common Java idiom is to use anonymous inner classes to define the concrete subtypes. That's how closures are most commonly implemented in Java.'' [It's not a closure as written, because the concrete subtype needs to be defined within S''''''ampleRow to have access to its data members. (Actually, as written it merely needs to be in the same package, but I'm assuming that's an oversight and the data members were really meant to be private, as that's more idiomatic Java.) It might be a good idea to clean the example up so that it actually does something, because it's currently too incomplete to draw any useful conclusions from. -- jt] ''S''''''ampleRow is passed to Function.perform(), so it doesn't need to be defined within S''''''ampleRow.'' [That's not a closure, then, it's a data structure passed to a method. The two are equivalent in functionality, but they're defined differently and have different implications for InformationHiding. A closure would implicitly have the ability to look at Sampl''''''eRow's members, which then wouldn't need to be exposed to other classes in the package. The confusion is mostly definitional: Java folks often take closure to mean any FunctionObject. But in the normal sense, a LexicalClosure must "close over" some variables - they appear free within the body of the code, but take their bindings from the surrounding lexical context. -- JonathanTang] ''It's still a closure, just not necessarily over a S''''''ampleRow. The anonymous inner class that extends Function has the lexical scope of the enclosing class (which could be S''''''ampleRow, but probably isn't).'' {I am still not clear how the strategy name in the RDBMS selects the proper method.} ''The function name in RDBMS was your solution. Mine doesn't say anthing about the use of a database. '' * I suggest you review the original problem statement above. If it is a different issue, then perhaps we should set it apart from that. Rather than "func", think of that column as perhaps a "strategy indicator". '''The decision to put it in the database was to avoid duplicate change-points when adding a new record.''' You can move the strategy selection to your code, but it appears that creates 2 change-points instead of one. * ''If you're willing to execute any method named in a database, then you can avoid changing (and compiling) code. I've never worked in such an environment, but I assume they are out there. Otherwise you'll have to name the method in compiled code. It's that simple.'' * You seem to be agreeing then that Eval has value in that it can reduce the effort of change in some cases? Both polymorphism and a case/switch list will require at least two change points for the scenario given. Eval can reduce it to one. -- top * ''Certainly. It provides that benefit if you are willing to execute code found in a database. Just know that once you do, the system executing your code inherits all security risks from your database.'' * Note that one can verify that a function/method name does not have "special" characters, to limit the "code" to being a function/method name and nothing else. * ''And?'' * It does not have to be open-ended. If we use it often (which is generally not the case in my experience), we can create an "evalFunc" wrapper to check the content to make sure it is only an alpha-numeric name. (Standard parameters are appended before Eval.) [''It isn't TableOrientedProgramming at all; unless you redefine TOP to be so all-encompassing that it subsumes pretty much everything under discussion.''] Ah, You caught me borrowing campaign strategies from the OO party ;-) ---- ''For such an example; I wouldn't use InternalPolymorphism--I would use if or case. If the logic was sufficiently nasty, I might even use a relation for that purpose, assuming a good relational implementation was handy (something more lightweight than even a NimbleDatabase, unless I already had a RDBMS around for other purposes). Perhaps if a language allowed declarative polymorphic dispatch on different values of the same type; that would be another solution.'' ''But your example is an extreme case, and perhaps a pathological one. Most examples of DynamicDispatch occurring in the wild are dispatches based on types and not values. A significant fraction of those are dispatch on a single argument.'' Examples? Note that I am not a believer in "big types". See ThereAreNoTypes. * ''Whether or not you believe in "types" as structural entities, "types" as sets/equivalence classes are a fact of life. And you should be able to dispatch on membership in such a set; any solution that doesn't allow that is crippled and dead-in-the-water--at least as a general-purpose mechanism.'' * Fact of life? Who's book? An example of "dead in the water" would be nice. ** OK, write me a table that allows me to dispatch as follows: Call foo() if the argument is an integer, call bar() if is a string; call baz() otherwise. You'll notice that all three sets (the integers, the strings of characters, and whats left) are infinite... ** ''I would prefer you put such a request in terms of a practical user need. As it is, it seems to revolve around language-specific issues.'' *** Snort. '''Your Change Impact Example 1''' above is ''far'' more contrived and pathological than the example I have given here. There are many examples of needing to do type dispatch as I have just described; and they aren't all DeviceDriver''''''s. :) *** ''Unsnort. I don't find it "contrived". If you have specific complaints on that example, then this is not the place to vent them. Anyhow, I am NOT an expert on static typing and TOP. I've grown to prefer dynamic typing (or lack of typing) and don't ponder statically typed TOP much. I have no interest in it.'' '' All OO languages handle SingleDispatch of that sort efficiently; and many handle MultipleDispatch efficiently as well. Some even due it externally to the classes involved; CommonLispObjectSystem generics are a fine example of that.'' ''Any suggestion that all DynamicDispatch should be done using tables because you can conjure up an example that is difficult to handle using "OO" techniques strikes me as yet another example of UniformityUberAlles--'''X''' can do '''f''' more easily than '''Y'''; so we should use '''X''' everywhere; even though '''Y''' might be better at other things. I could extend that argument even further and make the (absurd) claim that we should abandon declarative dispatch schemes (including both polymorphism and TableOrientedProgramming) in favor of imperative schemes such as hard-coded if or case statements; because hard-coded if/case statements can handle dynamic conditions more easily than the declarative methods. To wit; try encoding THIS as a table''. if (complex_and_changing_query_on_the_state_of_the_world() == TRUE) return do_this(); else return do_that(); ''Given that the complex_and_changing_query() is not an invariant; it can't be put into a table easily. It could, I suppose, but then some other entity would have to keep it up to date; otherwise the program would be incorrect.'' I am not sure what you are trying to illustrate here. * ''That TableOrientedProgramming alone isn't sufficient for everything. A point only relevant if one is arguing for use of OneAndOnlyOne dispatch mechanism. Given that I don't argue for such--I believe in HorsesForCourses--it doesn't matter to me.'' * I never said they were good for everything. However, they excel at managing complex and changing relationship between things. OO gets messy beyond simple inheritance and single-factor polymorphism. ** No, not necessarily. Perhaps C++ gets messy, but properties of any given OO language are not necessarily properties of OO. ** ''You seem to suggesting a specific incarnation of OO, not OO itself. Plus, if such dispatching involves lots of attributes, a data-centric solution is still going to be superior because managing boat-loads of attributes in code is harder than doing the same in a database in the vast majority of cases. Most business data comes from RDBMS anyhow, whether one wants it to or not. If all the data is not born and dies within a single OOP language, then you have extra conversion complexities. A paradigm conversion tax.'' ''All techniques for dispatch--simple StaticDispatch, SingleDispatch (dynamic), MultipleDispatch (dynamic), table-driven dispatch, and explicit conditional logic--have their place. The ones early on the list are faster and easier to reason about; but are less flexible then the ones later on the list. And each has their place.'' -- AnonymousDonor "Faster" perhaps, but "easier to reason about" is rather subjective or open-ended. ''Nonsense. In the case of StaticDispatch, one can determine exactly what is called before the program is run. For SingleDispatch, MultipleDispatch, and TableOrientedProgramming, it gets progressively harder to make such determination--especially if the dispatch table can be modified during the program's execution.'' * Sounds like you are selling static typing techniques so that you can check as much as possible at compile time, not necessarily OO. I suppose you are not fond of Python and Smalltalk, I would guess. ** ''I'm not selling anything. Especially not StaticTyping; although TypeInference is always a useful thing to do, either as a compiler optimization or as a way of detecting defects. And I've nothing against Python or Smalltalk,'' Plus, tables appear to scale better. One can incrementally go from one-way dispatching to n-way dispatching with far fewer structural changes. ''Appear? "Maybe" arguments aren't very effective. "Appear" means "I don't know, but I'll offer this up as conjecture."'' ''A solution waiting for a problem. At any rate, in languages with MultiMethods, going to n-way dispatching is a trivial exercise as well.'' MultiMethods is mostly just static tables and static QueryByExample. ''And in many instances of dispatch, the binding between the attributes of the arguments to dispatch on and the function to select is indeed static. Were it dynamic; I wouldn't bother with tables; I'd just use conditional logic for the reason outlined above.'' ''SingleDispatch languages make it harder, as you have to resort to the VisitorKludge, er, pattern or similar things... but that is a problem with less-expressive programming languages rather than with OO per se. And if someone wanted to make a table-driven dispatching mechanism in an OO language, it isn't that hard to do.'' Then the next step is to get rid of NavigationalDatabase habits, you have reinvented TOP the hard way. * What to NavigationalDatabase''''''s have to do with any of this, other than the tired old cliche that any data structure involving pointers is tantamount to CODASYL? Or databases at all, for that matter? Implementing dynamic dispatch of functions based on the attributes of their arguments--the subject of this debate--seldom if ever requires persistence, transaction semantics (ACID, etc), or any of the other services that databases provide. Don't confuse the RelationalModel with the RDBMS; you do yourself (and TOP) a grave disservice when you do. TableOrientedProgramming techniques ''are'' useful (though I don't think they should be universal); but they would be far less useful were they to require a database engine (even a NimbleDatabase) be present. Relational tables are useful data structures even when not in the context of a database. [Uh, I wrote the whole paragraph above; why was it ReFactor''''''ed to look like two different persons?] [[Your other personality isn't aware of your first personality. We'll try doubling the dosage. ;-) ]] Sorry. I did it because I thought it was from too different authors. Spacing has been lacking in so many replies lately that I thought it was yet another instance. By the way, I added MinimalTable to clear up the definition or description of "table". Maybe we can make a similar rough ranking for "navigational structures". -- top ---- The distinction given above appears to me to be one of syntax. (Although the whole SetsAndPolymorphism debate, from where this comes, does bubble to the surface). One could write an OO language where one writes method(object,a1,a2) rather than object.method(a1,a2); one can even do this with EssExpression''''''s (method object a1 a2). Likewise, one can use any one of those syntaces to effect a relational query--regardless of whether or not the thing returned was a table full of data, or a table full of functions. And, the disucssion is superfluous on another level--evaluator functions can ''implement'' polymorphism. CommonLispObjectSystem is based on this. On the other side of the coin, the calling conventions for many "mainstream" programming languages can be viewed simply as highly-optimized (and in some cases, somewhat crippled) eval functions. In other words, you're all talking past each other. The same can be said for SetsAndPolymorphism. --ScottJohnson I agree, but some are making a big deal about it. -- top ''You would be one of the guilty parties here; not the only one certainly.'' ---- '''Security Concerns''' "eval" relies on interpreting data at run time. That's an unacceptable security risk for most professional software. That I don't see is any convincing reason to use a non-OO environment in the first place. ''"eval" interprets (or compiles) a code segment retrieved from a database before it executes it. That code segment could do anything, from formatting the hard drives to emailing confidential information.'' An object method executes (may interpret and compile) a subroutine retreived from a database before it executes it. That code segment could do anything, from formatting the hard drives to emailing confidential information. What's the difference? ''None of my object methods execute code retrieved from a database. All of them execute compiled (and tested) code. Are you saying that because it's possible to write insecure code we should not bother to write secure code? I don't think I'm following your argument.'' Depending on the particular runtime technology, an eval mechanism can be made just as safe as compiled code with no big extra programming effoprt. The mechanism has been used in industrial systems for dispatching hot-updates, that obviously cannot be solved by pretending that all the code executing at runtime has to come from a statically fixed image. There's nothing that makes virtuable table dispatch mechanism of OO languages inherently safer than eval. ''How does one make an eval mechanism just as safe as compiled code?'' Very easy, you can run eval in a sand box, and you can use cryptographic signatures. What makes compiled code extra safe, after all ? ''And you're arguing that running eval in a sand box and/or using cryptographic signatures is requires no "big extra programming effort"?'' Unless you're programming in asembly or machine code, using cryptographic signatures is trivial, while platforms like Java come with sand boxes ready made for you, making it a trivial one liner to run arbitrary code inside a sand box. But you haven't answered what makes statically deployed code any safer. ''Java comes with a sand box? Where do I find it? Statically deployed code is safer because it can be tested. New instructions aren't fed to it after deployment by potentially malicious users who gain access to the database.'' Malicious user can get access to the database just like malicious users can get access to the file systems where your "statically" deployed code resides. Operating systems do not have extra-measures for protecting file data any more than databases have measures for protecting data. Code deployed dinamically can be just as tested as code deployed once and for all. ''But executing code loaded from the database adds the security risks of the database to the security risks of the file system. We generally have to accept the risks of file systems. We don't have to accept the risks of databases.'' FYI java comes with java.lang.SecurityManager that by default is not instantiated. Running a sand boxed application is just as easy as command line option java -Djava.security.manager or runtime System.setSecurityManager(new SecurityManager()). ''The SecurityManager is not the entire sand box. Each browser or applet viewer provides its own sand box. I've written one and I wouldn't categorize it as no "big extra programming effort."'' ---- '''Page Rationale Discussion''' ''The page is about BryceJacobs trying to justify his approach of putting code into the database and using eval to implement dynamic dispatch, he calls it TableOrientedProgramming. He started the page when he was critiqued for that practice. No one claims eval can't do what polymorphism does, the claim was that eval is frowned upon in the languages that allow it, there are better ways to structure code that are far more maintainable, and more efficient than using evaluated strings as your own hacked up dispatching mechanism. Most languages have a built in method of doing dynamic dispatch, one need not resort to evaluating strings to accomplish the task.'' I guess some of you guys are so obsessed with demolishing top that there's little room for discussing the technical issues for real. This page is entitled eval versus polymorphism, and somebody just claimed above that eval was unrelated to polymorphism. ''I've watched this page from it's inception, and it was Bryce, doing exactly as said above.'' Mind you, there are real arguments against using eval unnecessarily, but none that I've seen so far. And besides execution of dynamically loaded code is essential for coming up with such powerful features as hot updates on continuously running systems. ''Great, but that's not what was being discussed. He's using it to implement dynamic dispatch, for no reason other than avoiding OO.'' As to the pearl that "eval" is "frowned upon" (boy, I like this expression) in the languages that "allow" it (did you somehow mean languages in which eval is the cornestone ?), well you can read for yourself the scheme report, that considered it so important that has a chapter on its own.And in many fine places where they teach computing science, you wouldn't be able to pass the first course if you couldn't write your own eval, much less if you did "frown upon". FYI, eval interprets strings only in PERL et. comp., not in Lisp or Scheme. ''Again, of course eval is important. No one is denying that, but Bryce isn't using Lisp and Scheme where eval works on native data structures. He's using eval to execute strings from a database to fake up dynamic dispatch. Do you not acknowledge a difference? Do you not consider that a poor use of eval, reinventing features that already exist in the language? Even Lispers and Schemers, from what I've seen, don't necessarily want you using eval, though they consider it vital to understand. Don't pretend this is some high level intellectual argument, this is Bryce being Bryce. Every time someone says something that he feels attacked on, he starts a page and tries to promote his own brand of programming, and apparently, at least in his mind, has never been wrong.'' ---- '''Eval And Polymorphism''' I am not sure how "eval" relates to polymorphism. It appears that eval is being used to create an object structure (unifying code and data) in a non-OO environment. I don't see the necessary support for polymorphism has been presented for comparison. ''Executing code retrieved from a database differs from an "object model" in that there is no encapsulation, polymorphism or inheritance. So it doesn't qualify under the general definition of object oriented programming.'' Well, but eval is the ultimate form of polymorphism. You can't get any more powerful than eval. As for object oriented programming, it is orthogonal to polymorphism, as demonstrated by countless non-OO but still supporting polymorphism programming languages. This page seems to assert that one can replace a conventional runtime polymorphic dispatch mechanism such as those supported by Java, Smalltalk, C++, etc, with eval. Thus getting in return a mechanism that is at least as expressive and powerful as vtables or what else. The assertion seems trivially true, so what's the fuss all about ? In modern software most code is loaded at runtime from some place other than a big stinking executable image, be that place a DLL, JAR, CAB, .so or whatever is called. Storing code in a database is not in itself such a terrible idea. File systems are much less secure places than databases, and one can easily imagine a system in which a database is used to store code, including with proper versioning and dependency management, heck it may even be done by default in the next version of windows where the file system is a proper database. [Side bar: I am not TOP, but I did start this section of discussion. I have had no prior exposure to "eval" before this page and I do not believe the connection between eval and polymorphism has been well developed. I am interested in discussing how eval might support an OO approach and may find it useful in the future. Let's try to keep the focus on a technical comparison of the two approaches and forget the psychological analysis about why someone may have initially proposed the idea.] ''OK, eval and OO are orthogonal. If you know JavaScript, try typing eval("alert('hello world');"); to see eval in action. It is a way to take a string of characters or an expression, and execute them as code. In reality you only need two functions to build an interpreter for any language, EvalApply. It's a good start to understanding how languages work in the first place. But they are primitive functions, many other abstractions are layered on top of them to really fill out a language, but neither have anything to do with OO. No one proposed any connection, what was said is that using eval essentially gives you dynamic dispatch to any function, which is technically true, but also silly. If your program consists of nothing more than eval(rs["code"]), you are asking for trouble as this will be a huge maintenance burden. While obviously flexible, there are far more maintainable methods of dynamically dispatching methods at runtime, OO being one approach, multimethods being a better approach, both superior to eval in terms of readability and maintainability.'' [Technically, MultiMethods are not the best approach. PatternMatching is about equal in power but deals better with certain change patterns than others (it handles complex data structures better, while multimethods handle complex code structures better). PredicateDispatching beats them both, however, as both fall out as special cases of the predicate dispatching model. See CecilLanguage until PredicateDispatching gets filled out as a page. -- jt] ''Interesting, I hadn't heard of PredicateDispatching, please fill out the page if you know more about it.'' I am not suggesting Eval be heavily used in the way many OO designs tend to use polymorphism. (OO tends to overuse polymorphism IMO). But in a Strategy-like pattern where the attributes come from a database, it can reduce the number of change points for new records/objects, as shown above. It is another technique that can sometimes simplify things. If security or speed are more important than change-effort reduction, then it may not be appropriate (in which case I would use a case/switch statement.) -- top '''Preparing to Summarize''' The consensus of this discussion seems to be that although eval may be an interesting language construct, eval by itself is not comparable either to OO concepts in general or polymorphism in particular. Although an OO-like environment based on eval could possibly be created, this environment has not yet been described nor presented, hindering any further discussion of this topic. ------------ ''Actual Usage Patterns'' The most common place I see this technique used is in table-driven '''menu''' systems. I have seen at least four different applications outside of those I originated that use Eval or an Eval-like technique for menus. Web applications will tend to store the script name and supply that to an HREF tag during page generation. Rather than a direct Eval, it is the web browser that "executes" the script. Calling a URL to a dynamic HTML page is more or less a function call. Even static languages without an Eval can be used for this. -- top ------- See also: DynamicStringsVsFunctional