[erlang-questions] Fear and Loathing in Programming La La Land
Evan Miller
emmiller@REDACTED
Fri Mar 30 15:01:29 CEST 2012
On Thu, Mar 29, 2012 at 9:47 PM, Michael Turner
<michael.eugene.turner@REDACTED> wrote:
> "Requiring parameters in the constructor packs much more information
> per line of code than the create-set-call convention, and so I am able
> to read it more quickly."
>
> Yes, IF you know the order of parameters and their meanings in
> advance, OR you have some way to look those up almost instantly. True
> in some cases, not in all. You can read any piece of code very fast.
> The challenge is more often in *understanding* what you're reading. If
> the name of the class/type is suggestive, e.g., Point, then
>
> P = Point(0,1)
>
> might seem pretty obvious: x=0, y=1. But how about this?
>
> R = Rect(a,n0,r,v)
For me "readability" has to do with having a lot of code on-screen at
once, and not the number of tokens I can pass my eyes over per second.
I find your chained constructor example to be highly readable for this
reason. But setting one attribute per line of code is not readable in
this sense.
In my own experience the argument semantics are usually obvious from
the context of well-written code. I am always forgetting the argument
order to "qsort", for instance. Is it the number of elements first or
the size of the element? But when I see
qsort(table, var_count, sizeof(varlookup_t), &compare_elements)
I know the answer instantly. Of course, if the original author has
inadvertently switched two arguments to a constructor, it will be
harder to debug. So in my mind, if you have the luxury of working with
very good code in familiar territory, "initialize everything" is the
preferable style. But if you are condemned to working with inferior
code, or code that uses unfamiliar libraries, the alternative will
prove to be more merciful.
Evan
>
> Do the parameters refer to the *ranges* [a,n0] and [r,v]? Or to
> *points*: (a,n0) the lower left, and (r,v) the upper right? The
> following (notional) syntax for construction and setting instance
> variables would make it clear:
>
> R = Rect().lowerleft(a,n0).upperright(r,v)
>
> and it doesn't exclude other equivalent constructions for the same type, e.g.
>
> R = Rect().x_range(a,r).y_range(n0,v)
>
> " Initialize-everything also reduces the potential for bugs, because
> with create-set-call there become N! ways to initialize an object,
> instead of just 1."
>
> N! overstates the *likely* combinations. Order of initialization is
> typically idiomatic (e.g., people set x before y, usually). Explicit
> setting of parameters that ordinarily default to reasonable values
> will tend to follow other initializations that are almost always set
> explicitly.
>
> Create-all-at-once has its pitfalls too. I mentioned a job where a
> co-worker said that constructors with 22 parameters were OK because
> you could just copy a working constructor call from some other code,
> then make any mods you felt necessary. I immediately pointed out to
> him that you might be copy-pasting bugs -- bugs that were latent in
> the code you were copying, and that would manifest themselves much
> more perfidiously in what you were copying to.
>
> If create-set-call is the dominant style, I think people should at
> least enforce rules about states reached by setting certain values,
> and exceptions thrown if operations are performed prematurely, on any
> not-quite-yet-initialized object.
>
> I don't think there's any single right way. Readability and
> conciseness will always trade off in complex ways, depending on
> people's preconceptions. I usually prefer a mix, when I write code.
>
> -michael turner
>
> On Thu, Mar 29, 2012 at 10:50 PM, Evan Miller <emmiller@REDACTED> wrote:
>> Programmer "types" aside, ease of writing code is not the only desideratum.
>> Something missing from your discussion is program readability and
>> maintainability. Requiring parameters in the constructor packs much more
>> information per line of code than the create-set-call convention, and so I
>> am able to read it more quickly. Initialize-everything also reduces the
>> potential for bugs, because with create-set-call there become N! ways to
>> initialize an object, instead of just 1.
>>
>> It is short-sighted to consider only programmers' stated preferences when
>> designing an API. I am sure programmers in the study would also have
>> preferred not to write code comments or unit tests if given the option to
>> leave early for lunch. I am reminded of a quotation that appeared in my high
>> school's writing center:
>>
>> "What is written without effort is in general read without pleasure."
>> --Samuel Johnson
>>
>>
>> Evan
>>
>> On Thu, 29 Mar 2012 02:32:33 -0500, Richard O'Keefe <ok@REDACTED>
>> wrote:
>>
>>> I'm to the Psychology of Programming Interest Group mailing list.
>>> In a discussion of naming, reference was made to a body of work
>>> containing
>>> Usability Implications of Requiring Parameters
>>> in Objects' Constructors
>>> by Jeffrey Stylos of CMU
>>> and Steven Clarke of Microsoft
>>> at http://www.cs.cmu.edu/~NatProg/papers/Stylos2007CreateSetCall.pdf
>>>
>>> The abstract reads
>>> The usability of APIs is increasingly important to programmer
>>> productivity. Based on experience with usability studies of
>>> specific APIs, techniques were explored for studying the usability
>>> of design choices common to many APIs. A comparative study was
>>> performed to assess how professional programmers use APIs with
>>> required parameters in objects’ constructors as opposed to
>>> parameterless “default” constructors. It was hypothesized that
>>> required parameters would create more usable and self-documenting
>>> APIs by guiding programmers toward the correct use of objects and
>>> preventing errors. However, in the study, it was found that,
>>> contrary to expectations, programmers strongly preferred and
>>> were more effective with APIs that did not require constructor
>>> parameters. Participants’ behavior was analyzed using the
>>> cognitive dimensions framework, and revealing that required
>>> constructor parameters interfere with common learning strategies,
>>> causing undesirable premature commitment.
>>>
>>> The study was done in 2005.
>>> We're talking about the difference between
>>>
>>> fs = new FileReader("foo/bar.txt", Sharing.NONE);
>>> ln = fs.ReadLine();
>>> ...
>>>
>>> and
>>>
>>> fs = new FileReader();
>>> fs.SetFileName("foo/bar.txt");
>>> fs.SetSharing(Sharing.NONE);
>>> ln = fs.ReadLine();
>>> ...
>>>
>>> I think this is worth bringing up here because if functional programming
>>> is about anything at all, it's certainly about NOT setting up a value one
>>> field at a time!
>>>
>>> Their sample was carefully chosen to include three kinds of programmers:
>>>
>>> * OPPORTUNISITC programmers are more concerned with productivity
>>> than control or understanding. For these programmers objects
>>> that required constructor parameters were unfamiliar and
>>> unexpected, and even after repeated exposure these programmers
>>> had difficulty with these objects.
>>>
>>> That is, they just didn't "get" the idea of constructors having
>>> parameters.
>>>
>>> * PRAGMATIC programmers balance productivity with control and
>>> understanding. These programmers also did not expect objects
>>> with required constructors, and while pragmatic programmers
>>> were more effective than opportunistic programmers at using
>>> these objects, the objects still provided a minor stumbling
>>> block and these programmers preferred the flexibility offered
>>> by objects that used the create-set-call pattern.
>>>
>>> Remember, this was all about .NET. Failing to expect
>>> constructors with parameters in C# is like failing to expect
>>> assignment statements in C.
>>>
>>> * SYSTEMATIC programmers program defensively and these are the
>>> programmers for whom low-level APIs are targeted. These
>>> programmers
>>> were effective at using all of the objects; however, they preferred
>>> create-set-call because of the finer granularity of control it
>>> offered by allowing objects to be initialized one piece at a time.
>>>
>>> The purpose of the study was to provide guidelines for API designers at
>>> Microsoft: apparently they now recommend create-set-call. Remember,
>>> that's the idea where you create an object without saying *anything* about
>>> what you want it to be and then successively kick it into shape.
>>>
>>> They later say
>>>
>>> [Systematic programmers] want not just to get their code working,
>>> but to understand why it works, what assumptions it makes
>>> and when it might fail. They are rare, and prefer languages that
>>> give them the most detailed control such as C++, C and assembly.
>>>
>>> I'd like to think of myself as a systematic programmer. I certainly like
>>> to understand all those things. But if I preferred assembly I would not
>>> be writing in the Erlang mailing list! The basic conclusion seems to be
>>> that you should not design APIs for such rare animals.
>>>
>>> I made what I thought were three obvious points:
>>>
>>> (1) There is a confounding factor in the study: the create-set-call style
>>> lets you *name* the information going into an object, while at that
>>> time the full-initialisation style did not. There are constructors
>>> for System.IO.FileStream with six arguments; maybe more. It seemed at
>>> least *possible* that if the subjects had been given a third choice,
>>> constructors with *named* parameters, they might have preferred that.
>>> Because the study didn't include such a choice, we certainly cannot
>>> use it to argue *against* that style.
>>>
>>> (2) C# 4.0 has named (and optional) parameters, so the study is no longer
>>> adequate to tell us about good API design in C#.
>>>
>>> (3) If there are programmers out there who *don't* care much about
>>> understanding what they are doing, I certainly don't want them writing
>>> anything that might in any way affect me or anyone I care about.
>>> If they just don't "get" constructors with parameters, that's really
>>> scary.
>>>
>>> A lengthy discussion has followed in which I've felt rather lonely.
>>> I'm being beaten about the head for not noticing things in the study
>>> that I did notice, and for being rather elitist. One quote:
>>>
>>> We don’t have the luxury of dismissing these types of programmers.
>>> While it might strike you with terror that these programmers exist,
>>>
>>> It doesn't frighten me that they _exist_,
>>> it frightens me that they are _programming_.
>>>
>>> they are successfully building applications in many different
>>> domains.
>>> They may work differently to you and many other programmers but
>>> that
>>> doesn’t necessarily mean that the code they create is worthless.
>>> Within the Visual Studio team at Microsoft we’ve devoted efforts to
>>> attempting to make them successful by adapting to their workstyles
>>> when appropriate.
>>>
>>> I find myself wondering just how "successful" their applications really
>>> are.
>>> Oh no! I hope they're not writing climate modelling code! That would
>>> explain so much... (Yes, I've looked at the code in the ClimateGate
>>> dump.)
>>>
>>> Frankly, I've turned here for a bit of comfort. If anyone likes
>>> completely
>>> initialising things rather than smacking one field at a time, surely I
>>> will
>>> find such people here.
>>>
>>> Am I wrong? Would *you* be happy opening a file in C by doing
>>>
>>> FILE *f = malloc(sizeof f);
>>> set_title(f, "foo/bar.txt");
>>> set_access(f, "r");
>>> gets(f, buffer);
>>>
>>>
>>> _______________________________________________
>>> erlang-questions mailing list
>>> erlang-questions@REDACTED
>>> http://erlang.org/mailman/listinfo/erlang-questions
>>
>> _______________________________________________
>> erlang-questions mailing list
>> erlang-questions@REDACTED
>> http://erlang.org/mailman/listinfo/erlang-questions
More information about the erlang-questions
mailing list