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

[REBOL] Re: Tools for Rebol Coders

From: joel:neely:fedex at: 6-Jan-2002 8:20

Hi, Sunanda, Minor quibble, and other thoughts... [SunandaDH--aol--com] wrote:
> So my serious suggestion is for lint.r named after the > traditional C program that tells you just how many rules > you've possibly broken. A Rebol Lint checker could for > example highlight possible problems in this code: > > myFunc: func [Offset Size] > [ > MyLayout: layout [button "hello"] Offset > View/New MyLayout "My Layout" > ] > > -- Function header doesn't specify datatypes > -- "Size" defined in function header but not used > -- "Mylayout" created as global
Setting global "MyLayout" (MyLayout might have already existed, rather than being created, and it's entirely possible -- style arguments aside -- to write one or more functions which initialize global data.)
> -- "Offset" in Layout evaluated by not assigned > -- "My Layout" string in View/New evaluated by not assigned > -- No explicit Return statement >
The last one gets closer to my puzzlement over how to write any sort of linting, prettyprinting, etc. for REBOL, given the dynamic nature of the language. I probably won't say this as concisely as I'd like (I don't have time to use fewer words.) In a "fall-through" exit, the value of a function is the value of the last expression evaluated. This is A Good Thing, because I can write: delta: func [a [number!] b [number!]] [ either a < b [b - a] [a - b]] without cluttering up the desired expressions with a bunch of RETURN calls that add nothing to the function. Hmmmm... I think to myself, "Why not a warning if the last expression returns an UNSET value?" For example: printdelta: func [a [number!] b [number!]] [ either a < b [print b - a] [print a - b]] This raises some issues: 1) Maybe I wanted to define a function that is evaluated solely for its (side-)effect and not for a value. This is not uncommon. In languages that give a return type in the function prototype it's easy to distinguish between void foo (...) {...} and int foo (...) {...} to know what the programmer may have intended. We don't have any such hint in REBOL. 2) There are other ways to write the above function in conventional REBOL style, including some that nest expressions quite deeply, as in: printdelta: func [a [number!] b [number!]] [ print either a < b [b - a] [a - b]] The unique "expressional" style of REBOL leads me to think that a lint-like program would have to be capable of full- blown expression (including data type) analysis to be able to determine the type of the last expression (or even to *find* the last expression!) 3) The previous issue becomes even more pronounced when one considers the use of (first-class!) functions as arguments to other functions: foodelta: func [foo [function!] a [number!] b [number!]] [ foo either a < b [b - a] [a - b]] where one must understand something of the behavior of *each* FOO to know whether there's a return-type inconsistency, which implies that different uses of FOODELTA might need to get different warning messages depending on the argument of the moment... 4) REBOL is a dynamic language which only constructs function values by actually evaluating code. Given the ability to construct the blocks that are passed to FUNC, MAKE OBJECT!, etc... one may have no idea from the static text what will happen at run time. The only escape I see from all of this is to have a version of REBOL that requires the result type(s) of functions to be specified in the prototypes as well, and specifies the type signatures of functional arguments (and returned values) also -- a non-trivial change IMHO. -jn- -- ; sub REBOL {}; sub head ($) {@_[0]} REBOL [] # despam: func [e] [replace replace/all e ":" "." "#" "@"] ; sub despam {my ($e) = @_; $e =~ tr/:#/.@/; return "\n$e"} print head reverse despam "moc:xedef#yleen:leoj" ;