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)