C:\Documents and Settings\MILLERM1\Desktop\when-examples.e
|
# .............................................................................
pragma.enable("easy-return")
pragma.disable("explicit-result-guard")
pragma.enable("easy-when")
pragma.enable("when-sequence")
# account, service, option, and combio are stubs barely large enough
# to enable the example to run
def account {
to getCurrency() {}
to makeOffer(amount :int) {}
}
def service {
to getCurrency() {}
to getPrice() {return 3}
to perform(payment) {}
}
def option {
to getPrice() {return 4}
to exercise(hold) {}
}
def combio {
to makeOption(fromCurrency, toCurrency, toAmount :int) {}
}
################## MarcS' sequential version ####################
#immediate call version
# few intermediate variables are necessary
if (service.getCurrency() == account.getCurrency()) {
service.perform(account.makeOffer(service.getPrice()))
} else {
def option :=combio.makeOption(account.getCurrency(),
service.getCurrency(),
service.getPrice())
def payment := option.exercise(account.makeOffer(option.getPrice()))
service.perform(payment)
}
############ MarcS' slavish when-chained version ####################
# naive, thoughtless, brutal, slavish when-chained
# created by cranking the syntax mechanically from immediate call
# to when-chain
# The general clumsiness of having to make more intermediate result vars
# makes the getting of the service price "when needed" truly
# painfully clumsy. We learn that you want to get it early, before you fully
# understand how much you will need it later.
# Currently, you need to put "\" at the end of the when(blah) line
# if you want to put the "and then" symbol "->" on the
# next line. Can this be fixed?
when (def myCurrency := account <- getCurrency())
-> (def servCurrency := service <- getCurrency())
-> {
if (servCurrency == myCurrency) {
when (def price := service <- getPrice()) -> {
service <- perform(account <- makeOffer(price))
}
} else {
when (def servPrice := service <- getPrice())
-> (def option := combio <- makeOption(myCurrency,
servCurrency,
servPrice))
-> (def optionPrice := option <- getPrice())
-> (def payment :=
option <- exercise(account <- makeOffer(optionPrice)))
-> {service <- perform(payment)}
}
}
################## MarcS' when-based version ####################
#somewhat thoughtful, evolved event sequenced
# the big change is, we get the servprice at the beginning in
# parallel with the currency brands, solving the problem observed
# in the comments in the slavish when-chain version.
# Fascinating result: the event sequencing has disappeared, i.e.,
# it is now all normal "easy-when" clauses
# the nested when has not been wiped out by event sequencing because
# it is inside an else clause
when (def myCurrency := account <- getCurrency(),
def servCurrency := service <- getCurrency(),
def servPrice := service <- getPrice())
-> {
if (servCurrency == myCurrency) {
service <- perform(account <- makeOffer(servPrice))
} else {
def option := combio <- makeOption(myCurrency,
servCurrency,
servPrice)
when (def optionPrice := option <- getPrice()) -> {
def payment :=
option <- exercise(account <- makeOffer(optionPrice))
service <- perform(payment)
}
}
} catch prob {
println("service failed: " + prob)
}
# Normal easy-when: no additional example is needed, the above is
# already a normal easy-when!
################## MarcS' __when-based version ####################
# Note: __when version not ever interpreted, probably has syntax errors
# version using __when. The thunk clause is just big enough
# to make it clumsier. I dislike the indentation I have used
# for this more than the indentation I have used in the others,
# perhaps someone else can do better.
# the intermixing of braces and parentheses feels more disturbing
# for me when I try to put on my non-lambda beginner hat (well,
# actually, it disturbs me even without the beginner hat :-).
# I have used markm's intermediate variable with a when.broken
# for the error handler. Seems ok. Perhaps 3-arg allFulfilled is not required.
def prob := __when.allFulfilled([def myCurrency := account <- getCurrency(),
def servCurrency := service <- getCurrency(),
def servPrice := service <- getPrice()],
thunk {
if (servCurrency == myCurrency) {
service <- perform(account <- makeOffer(price))
} else {
def option := combio <- makeOption(myCurrency,
servCurrency,
servPrice)
__when(def optionPrice := option <- getPrice(),
thunk {
def payment :=
option <- exercise(account <- makeOffer(optionPrice))
service <- perform(payment)
})
}
})
__when.broken(prob, thunk {println("service failed: " + prob)})
################## Dean's sequential version ####################
## the "simple" version used patterns that in other circumstances lead to
## TOCTOU vulnerabilities, so I've introduced appropriate temporaries here.
## This also avoids fetching the values twice, which may be surprisingly
## expensive. The "simple" example also had the service expression twice.
## Since that's the heart of the operation, that is especially bad code to
## duplicate. For example, you'd hate to fix a bug in the service
## invocation in just one branch of the if.
# cleaner immediate call version
def myCurrency := account.getCurrency()
def servCurrency := service.getCurrency()
def price := service.getPrice()
def payment := if (servCurrency == myCurrency) {
account.makeOffer(price)
} else {
def option := combio.makeOption(myCurrency, servCurrency, price)
option.exercise(account.makeOffer(option.getPrice()))
}
service.perform(payment)
################## Dean's when-based version ####################
# transformation to when-based approach
def myCurrency := account <- getCurrency()
def servCurrency := service <- getCurrency()
def price := service <- getPrice()
def payment := when (myCurrency, servCurrency) -> {
if (servCurrency == myCurrency) {
account <- makeOffer(price)
} else {
def option := combio <- makeOption(myCurrency, servCurrency, price)
option <- exercise(account <- makeOffer(option <- getPrice()))
}
} catch prob {
println("service failed: " + prob)
}
service <- perform(payment)
########### MarkM's translation to a __when-based version #########
# transformation to when-based approach
def myCurrency := account <- getCurrency()
def servCurrency := service <- getCurrency()
def price := service <- getPrice()
def payment := __when.allFulfilled(
[myCurrency, servCurrency],
thunk {
if (servCurrency == myCurrency) {
account <- makeOffer(price)
} else {
def option :=
combio <- makeOption(myCurrency, servCurrency, price)
option <- exercise(account <- makeOffer(option <- getPrice()))
}
},
def _(prob) {
println("service failed: " + prob)
})
service <- perform(payment)