Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

[REBOL] RFC on support for user-defined "types"

From: joel::neely::fedex::com at: 11-Jun-2002 10:34

IANARTE, but I suspect that the level of effort to allow users to define additional DATATYPE! values might be non-trivial. That assumption motivated me to wonder about whether there could be some simpler enhancements that might still add value to the development of reliable scripts, and led to the following train of thought. There are at least two obvious virtues to the ability to declare data types for functional arguments: 1) Documentation -- the declarations make it easer for someone who is reading the source for the function (or its HELP) to understand what it expects/does. 2) Error handling -- an error in typing can be caught at the point of the function invocation, rather than more deeply (at some point where a type-inappropriate use is made of the argument). This usually assists the process of finding, understanding, and correcting the error. It's nice to have the capability of detecting errors as early as possible, and at the level of an expression that is most likely to be recognizable (both as to location in the script and purpose). AFAICT, the notation somefunc: func [a [typex!] b [typey! typez!] ...] [ ... ] could be understood as an interpreter-mediated (and therefore much faster, with more meaningful error messages) equivalent of somefunc: func [a b ...] [ if not typex! = type? a [ ;; complain about type of parameter a ] if none? find reduce [typey! typez!] type? b [ ;; complain about type of parameter b ] ... ] A truly extensible language allows the programmer to define new types as needed for a convenient "conceptual vocabulary" for expressing the ideas of specific applications. Mainstream OO languages usually handle this via the concept of "class", so that each new class serves as a user-defined type. Argument checking can include the notion of the class (or superclass) of which an argument must be an instance. Oooops! Wait! REBOL objects have no class! This means that the best we currently can do for object arguments is somefunc: func [a [object!] b [object!] ...] [ ... ] even when the programmer has specific kinds/flavors of objects in mind as the function is designed. However... REBOL does make use of the idea that one can access an attribute (e.g., invoke a method) of an object by name, so that any proposed use of an object may very well have expectations about a (minimum) set of attributes that the object should possess. To continue with my hypothetical example, the programmer may expect to use an INVERT method on the first parameter, and a MEMORIZE method on the second: somefunc: func [a [object!] b [object!] ...] [ ...blah blah blah... ... a/invert ... ... b/memorize ... ] and it would be quite nice to be told Excuse me, but you invoked SOMEFUNC with an inappropriate object as its first argument! instead of a message showing only some fragment of the innards of SOMEFUNC that might be unclear as to purpose and hard to locate. Therefore, I propose for discussion the idea of extending a function specification to allow a block of words after an OBJECT! type specifier, with the meaning that the corresponding argument would be required possess all of the indicated words within its context. In other words, we'd be specifying (a portion of) the *interface* that an object should possess, rather than a (non-REBOL) notion of "class". This would allow the above hypothetical function definition to be written as: somefunc: func [ a [object! [invert]] b [object! [memorize]] ... ][ ...blah blah blah... ... a/invert ... ... b/memorize ... ] to document/enforce that the first argument must possess an INVERT attribute/method and the second must have a MEMORIZE attribute/method, with the checking to be done by the interpreter at the/each point of function invocation (e.g., as type checking is done now). Feedback, comments, etc. welcome as always! -jn-