[e-lang] Computing Pi in parallel with several VATs. How to write it well ?

Mark Miller markm at cs.jhu.edu
Fri Jul 22 18:17:01 EDT 2005


Hi Pascal, welcome to E! Sorry for the delay in responding.


Pascal Grange wrote:
> This code is too spagheti-like for me but I was not able to do it best. This 
> spaghetiness is not a fact, just a feeling, for instance the printing of the 
> result is in the middle of the code, not the end...and so on. I know that 
> it's asynchronous but I would like to know if a E-programmer would code 
> that in a drastically different E-way.

Here's how I would alter the code fragment in your email message to address 
this issue.


pragma.enable("easy-return")
pragma.disable("explicit-result-guard")
pragma.enable("easy-when")

def [result,resolver] := Ref.promise()
var sum := 0 # sum often used below where "result" was originally used

for computer in computers {
     # We provide job to a computer
     if (currentInterval >= intervals.size()) {
         # every interval has been submitted, we stop (this is the simple
         # version)
         break
     }
     def launch_compute() {
         # This method launches a computation on computer.
         # It "recursively" calls itself when the computation
         # terminates so as to launch a new computation on the
         # same computer. If there are no more intervals to compute
         # then we stop computing and, if the computation has not
         # been stopped yet, we mark it with finished to true and
         # reveal the final result of the computation
         computing += 1
         def res := computer <- compute(currentInterval)
         when (res) -> {
             computing -= 1
             sum += res
             if (currentInterval < intervals.size()) {
                 launch_compute()
                 currentInterval += 1
             } else if (computing == 0) {
                 # no-one is calculating nothing and
                 # nothing remains to be computed...it is the end.
                 resolver.resolve(sum)
             }
         } catch e {
             e.printStackTrace()
         }
     }
     launch_compute()
     currentInterval += 1
}

when (result) -> {
     println(`result : $result`)
}


The first part calculates and reveals a result, the second part reacts to a 
revealed result. With this separation, the first part is now more amenable to 
being packaged as a reusable abstraction.


> A version of this algorithm for Mandala is available at 
> http://mandala.sf.net and I am convinced that my E implementation is 
> biased by my knowledge of the mandala one. Moreover, I am not 
> enough used with the E way of thinking ;)
> 
> So would you, E thinkers and experts, write this code this way ? If not, how ?
> Appreciations about the spaghetiness of E programs in general and how to
> avoid or become used with it would be appreciated.

With this one small change to your code above, I'd say it now reads like 
reasonable E code. Starting from this, I would seek to abstract the first part 
into a more generically reusable asynchronous control abstraction; but I'd 
guess that this abstraction issue is independent of E vs Mandala.

You can forward declare a variable with a "def" with no right hand side. You 
can then bind this forward declaration with "bind". So, depending on taste, 
you may instead prefer the rewrite


def result
...
             } else if (computing == 0) {
                 # ...
                 bind result := sum
...


I would consider either style to be good E code.

> P.S. I have joined a tgz with my source code just for the ones who may want
> to try. It uses code from Mandala, especially the math-related code so you
> will need mandala(http://mandala.sf.net) to run this and you will also need
>  to read my explanations in PiComputer.e and PiManager.e....

Some further points from the code in your attachment:

* The "# E Sample" comments from Walnut are only there to signal updoc that 
this html <pre> block should be processed as updoc input. There's no need to 
include this comment in E code.

* I prefer the spacing "} else {" to "}else{".

* You can parse a string representing an integer using the __makeInt function. 
Together with the "bind" style mentioned above, your

     var scale := 0
     var nbIntervals := 0
     try{
         scale := <import:java.lang.Long>.parseLong(args[0])
         nbIntervals := <import:java.lang.Long>.parseLong(args[1])
     }catch e{
         usage()
     }

would become

     def scale
     def nbIntervals
     try {
         bind scale := __makeInt(args[0])
         bind nbIntervals := __makeInt(args[1])
     } catch e {
         usage()
     }

which reduces the number of assignable variables.


* I'm curious: Why do you use BigDecimal?

* Rather than saying "def random := <unsafe:java.security.SecureRandom>()", 
you can just use the predefined "entropy".

* Many of the methods on Java's "StrictMath" class are available in E as 
methods on floating point numbers. So your

     <unsafe:java.lang.Math>.floor(scale / nbIntervals)

can be

     (scale / nbIntervals).floor()


* Instead of

     <unsafe:java.lang.System>.currentTimeMillis()

use

     timer.now()

* Different E programmers differ in their preference for string concatenation 
vs quasi-literals. MarcS prefers your

     println("Computed in " + stopChrono + " milliseconds")

style, while I prefer

     println(`Computed in $stopChrono milliseconds`)




> this is not a 
> code I am proud of ;-) especially I made a trick with files to have the 
> PiComputerManager find the PiComputers to avoid learning the E naming 
> service...by the way, is there a naming service in E ?

Any naming service, in order to be secure, must be bootstrapped by out-of-band 
introductions anyway. These out of band introductions invariably resemble your 
filename trick. So for what you're doing, using your filename trick directly 
is fine.

-- 
Text by me above is hereby placed in the public domain

     Cheers,
     --MarkM



More information about the e-lang mailing list