Closed KimBruce closed 7 years ago
@KimBruce writes:
This encourages a style of first checking the presence of a value with isSome or isNone and then performing an action. I.e., if "do" is applied blindly it can result in a "ProgrammingError" exception.
That's not correct. The whole purpose of do
is to avoid the need to check. It behave very much like do
on a collection: if there is no value, do
does nothing, and does not raise ProgrammingError
. If you look, there is exactly one circumstance that raises ProgrammingError
: asking none
for its value
.
That said, I think that it's a good idea to add the second method that you propose:
method ifSome ⟦U⟧ (action:Block1⟦T, U⟧) else (noneAction: Block0⟦U⟧) -> U
The advantage, as I see it, is that it avoids the need for a temporary variable. Comparing:
lookfor(5).ifSome{j: Number →
print "found {j}"
} else {
print "not found"
}
without ifSome(_)else(_)
def result = lookfor(5)
if (result.isSome) then {
print "found {result.value}"
} else {
print "not found"
}
I suggest that ifSome(_)ifNone(_)
is a better name, though, and that we include the
variant ifNone(_)ifSome(_)
as well.
Why the second version, the one that returns a value? Because if(_)then(_)else(_)
returns a value, and we want them to be parallel.
I think that I'm also in favor of following Scala and having Option
support the collection protocol.
I've made options also be sequences, so that they do follow the collections protocol.
In so doing, I've had to implement isEmpty
, which is identical to isNone
. This made me wonder if we should just replace isNone
by isEmpty
, rather than defining both. The complement ought then be called isFull
.
In other words, should our options have constructors empty
and full
(rather than none
and some
) and actuators ifEmpty(_)ifFull(_)
, etc.?
While pondering names, I remembered that the convention in Smalltalk is to use the suffix do
on an if...
name if the block gets an argument. So ifEmpty(_)ifFull(_)
would become ifEmpty(_)ifFullDo(_)
. Do we like that?
I don't see the point of making the two pieces non-parallel (one has a do and the other does not). Reasonable choices seem like:
ifEmpty(_)ifFull(_)
ifEmptyDo(_)ifFullDo(_)
ifEmptyThen(_)ifFullThen(_)
I personally prefer the first or third, as students are already used to if-then, but could live with the middle one.
Sorry, I wasn't very clear.
The point in using non-parallel names is that the clauses are not parallel. The full block gets an argument, and the empty block does not. The Do
suffix is intended to remind the user that the block needs a parameter, which will be bound to the object to which they can do something — just like the internal iterator.
To be consistent, we should also change while(_)do(_)
to while(_)repeat(_)
; in contrast, for(_)do(_)
is already named according to this convention.
Discussed with @KimBruce today. Agreed that ifFull
/ isFull
/ ifEmpty
/ isEmpty
are fine. Agreed not to use the Do
suffix.
Add valueIfAbsent(fun)
as method on options — returns value
or the result of applying fun
if there is no value.
This has been implemented in commit 36daea262. Still needs to be documented!
For consistency with the full–empty nomenclature, valueIfAbsent
is named valueIfEmpty
Now documented.
I'd like to propose a redesign of the option module. [Note: I understand that these modules are not particularly key to the language design, but ...] Currently the code is:
This encourages a style of first checking the presence of a value with isSome or isNone and then performing an action. I.e., if "do" is applied blindly it can result in a "ProgrammingError" exception. I'd like to propose a simplification that would force the user to confront the possibility of "none" before gaining access. I'd propose replacing the "do" method by
The intuitive semantics is that if the receiver has a value, apply action to it, otherwise apply the noneAction. I considered making it more functional, by writing instead:
but decided to keep it in the simpler form (though I could be convinced otherwise). An important advantage of this is that we could drop all the other methods of the type and classes. Thus everything above could be replaced by:
Here is a simple program that uses this new library (called option2):
Note that methods like isSome and isNone are easily definable from ifSome()else()
Interestingly, this style is closer to that Andrew advocated for the collection classes with methods like find()ifNone() and at()ifAbsent(). He convinced me (eventually) that this was a good style, hence these suggested changes!