Scripting style: Verbs in function names

Mark Waddingham mark at livecode.com
Fri Nov 4 10:57:01 CET 2016


If the goal is to emulate (to some extent) the English-like nature of 
script in our handler names, then I think it is instructive to look at 
the syntactic forms employed in the current syntax that exists. I can 
think of the following general forms:

    - properties:
        the X
        the X of Y

    - chunks (part access):
        item X of Y

    - predicates:
        X is [ not ] <something>
        there exists <something>

    - functions (in the mathematical sense):
        average(X, Y)
        sin(Z)

    - commands:
        encrypt X with Y using password Z
        import snapshot

A property is something which encapsulates a piece of state. Sometimes 
they are constants; sometimes they are read-only and reflect state that 
changes over time; sometimes they reflect something about the content of 
something, or an attribute of something and only change when explicitly 
set. Getting properties never have any side-effects; setting properties 
only has side-effects within their domain of concern (whether it be a 
library, or an object).

A chunk is something which allows access to a part of something. Again, 
sometimes they are read-only, sometimes settable. Getting chunks never 
have side-effects; setting chunks only have side-effects within their 
domain of concern.

A predicate is a test which returns true or false, and is to test for a 
particular condition. They never have side-effects.

A function (in the mathematical sense) takes inputs, and uses those 
inputs to generate output. If we want to be completely pure, then they 
should never have side-effects - they should be used for computational 
devices... i.e. Things which synthesize a result based on input values 
and related state.

A command is something which actually *does* something. Commands can and 
do have side-effects.

I'd perhaps further suggest that evaluating functions, predicates, 
chunks and properties should *not* be able to fail apart from due to 
mis-use (e.g. asking for an object which doesn't exist, trying to 
convert "ZOO" from base 10 to base 16). I think this is generally true 
in the engine, the most prominent exception which comes to mind being 
the 'url' chunk.

[ As a slight aside...

This latter sitation (functions being able to fail when it is not due to 
mis-use) is why we have the odd situation with functions being able to 
return two values (the result, and the actual return value). The reason 
this is actually not ideal is that you can easily write code which is 
not and cannot be made correct except by separating out onto multiple 
lines. e.g.

   processMyTwoBitsOfData url X, url Y

Here, if fetching url X fails, then the command will receive empty, and 
still get executed which is technically wrong in pretty much any 
scenario (after all, one of the url's could actually be empty by intent 
and so you the receiving function cannot tell the difference between a 
failure in fetching one of its arguments, and the argument actually 
being empty). In order to write this correctly you need to do:

   local tX, tY
   put url X into tX
   if the result is not empty then throw "fetching X failed"
   put url Y into tY
   if the result is not empty then throw "fetching Y failed"
   processMyTwoBitsOfData tX, tY

Of course, this might just suggest that the url chunk should throw an 
error in the case of failure; but that then violates the principal that 
things you cannot predict failure of *must* be explicitly checked for 
success. Unfortunately, however, the world is not perfect. ]

In contrast, commands (as they are performing an action, rather than a 
computation) can and do fail in ways you cannot predict. This is 
typically indicated by returning a non-empty result; with any actual 
returned value from a command being placed in it (in the case the 
command didn't fail). [ Note: Script now has the ability to set either 
the result or it from a command handler - by using return for value, and 
return for error ].

So, if the goal is to reflect English-like ness in our library function 
naming (in lieu of being able to actually define our own syntax directly 
in one of the above forms) then the following seem reasonable:

    - property-like things: The<property>[Of<thing>]

    - chunk-like things: <Chunk>Of<Thing> / TheNumberOf<Chunk>sOf<Thing>

    - predicates: Is[Not]<Adjective> / ThereIs(A|An)<Noun>

    - functions: <Noun> (with potential suffixes describing inputs)

    - commands: <Verb> (with potential suffixes describing inputs)

I realize here function/command are a little too general - they are 
difficult to abstract in a reasonable pattern as their naming will 
largely depend on what they are doing.

The case in question was a MIME library with the following parts:

    - a function which returns the version of MIME to use in the MIME 
header - MIMEVersion

    - a function which returns the mime type for a given extension - 
MIMETypeForExtension

    - a function which returns the list of extensions matching a 
wildcarded mime pattern - MIMETypeExtensions

    - a command which encodes the input in a MIME transfer encoding - 
MIMEEncode

    - a command which creates a MIME multipart document from an array of 
pieces - MIMECreateMultipartContent

    - a command which creates a MIME multipart document from a field - 
MIMECreateMultipartContentFromField

    - a command which creates a MIME multipart email from a pre-encoding 
multipart document and attachments - MIMECreateEmail

A naming scheme consistent with the above 'english-like' forms could be 
something along these lines:

The MIMEVersion is actually a read-only property:

     syntax: the MIMEVersion

     function form: mimeTheMIMEVersion

The MIMETypeForExtension is essentially a parameterized read-only 
property, or chunk:

     syntax: the MIMEType of extension <ext>

     function form: mimeTheMIMETypeOfExtension(<extension>)

The MIMETypeExtensions as currently posed is either a direct constant 
lookup, or a 'map' over a list of constants. I think it is reasonable in 
this case to consider a 'MIMEType' as either being a fixed string, or 
wild-carded string (at least restricted wild-carded - e.g. text/* but 
not t*t/plain):

     syntax: the extensions of MIMEType <mimetype>

     function form: mimeTheExtensionsOfMIMEType(<mimetype>)

THe MIMEEncode command is actually a pure function - it takes an input 
and produces an output entirely based on the input, it cannot fail:

     syntax: <data> encoded for <transfer-encoding> MIME transfer

     function form: mimeEncodeForMIMETransfer(<data>, 
<transfer-encoding>)

     ('for' suggested here because the transformation is *for* a purpose, 
not an end state)

The MIMECreateMultipartContent is again a pure function - it encodes a 
sequence of transfer-encoded parts into a multipart document:

     syntax: <parts> encoded as MIME multipart document <type> [ with 
<params> ]

     function form: mimeEncodeAsMIMEMultipartDocument(<parts>, 
<multi-part type>, <params>)

     ('as' suggested here because the transformation produces something 
which is an end state - a multipart document)

The MIMECreateMultipartContentFromField, again a pure function - it 
encodes the content of a field as a mime multipart document:

     syntax: <field chunk> encoded for MIME multipart document

     function form: mimeEncodeFieldAsMIMEMultipartDocument(<field id>)

The MIMECreateEmail is not truly a pure function as it can fail - it has 
to potentially load data from files in the attachment arrays. It also 
has quite a long argument list so is probably better considered a 
command:

    syntax: encode <body> as MIME email with subject <subject> from 
<sender> to <recipient> [cc <cc>] attaching <attachments> [ into 
<container> ]

    command form: mimeEncodeAsMIMEEmail pBody, pSubject, pSender, 
pRecipient, pCC, pAttachments

Are these names any better than the ones already used in the library? It 
is hard to say - naming preferences are highly subjective!

However, one thing which I think is useful to consider in mind is that 
difficulty in naming things can (in many cases) indicate that the design 
is of the API is perhaps not quite right. I did the above reimagining of 
the current names in the library without considering whether there was a 
better way to 'slice and dice' the functionality. (For example, would it 
be better to have the concept of a 'mime email object' which you use 
setters and getters to configure?).

Just my two pence.

Mark.

-- 
Mark Waddingham ~ mark at livecode.com ~ http://www.livecode.com/
LiveCode: Everyone can create apps




More information about the use-livecode mailing list