[e-lang] Sending files with E?

Jimmy Wylie Jr. jwylie at uno.edu
Mon Sep 29 18:08:33 CDT 2008


> The overflow is likely being caused because the 'copy' function is tail
> recursive, but E-on-Java doesn't implement tail call optimisation.

 Yeah, I figured that's what was going on.. I should have realized that.
Leftover, Scheme/Haskell habits, I guess.


> You can avoid the stack overflow (I think) by changing the (implicit)
> immediate call ('.') to a send ('<-') instead, e.g.
>
>       copy <- run(dispenser, output,    avail)
>
> This will have the subsequent evaluation of 'copy' occur in a separate
> turn. Rather than requiring another stack frame to evaluate it
> immediately, it will be evaluated later on. Now sending an N byte file
> requires a stack of some constant size -- i.e. a stack size of O(1).

I implemented the change, this fixed the problem... sort of.  If I send a
big enough file, I then get a heap overflow error (OutOfMemory Error - The
program writes about 4kb before overflowing).  I think after the number of
available bytes has been returned, I can divide that up into smaller chunks,
and call copy that many times, reusing the same output stream.  I'm not
quite sure how to implement this yet, because I wouldn't want to call copy
again until I'm sure the previous copy has finished. Any suggestions?


> You could create the promise before the first invocation of 'copy' and
> pass the promise through to the call to 'copy'. On its last invocation
> (i.e. if 'copy' is not invoking itself again), it simply resolves the
> promise it was passed, to indicate that the transfer is complete.
> Otherwise (on a recursive call), it passes the promise to the recursive
> call without resolving it. Would that work?
 I tried this, but it turns out that the promise for the entire copy
resolves before the charVow promises resolve and write to the outputStream.
Instead, I changed the code this way:

def copyHelper(dispenser, output, available, resolver) {
    traceline("copying")
    var avail := available
    traceline("this copy is called with " + available)
    if(avail > 0) {
             def charVow := dispenser <- read()
             when(charVow) -> {
                    traceline("byte: " + available + " is resolved")
                    output.write(charVow)
                    if(available == 1){
                       traceline("LAST BYTE WRITTEN!!!")
                       resolver.resolve(1)
                    }
              } catch problem {
                    println("something went horribly wrong")
                    traceline(problem)
              }
              avail := avail - 1
              copyHelper <- run(dispenser,output,avail, resolver)
    } else {
             return
    }
}

def copy(dispenser, output, available) {
    def [copyPromise, copyResolver] := Ref.promise()
    copyHelper(dispenser, output, available, copyResolver)
    return copyPromise
}

I figured that the last byte written would be the one associated with the
function call where available == 1.  So I added a check for that in the
when-catch, so the promise would resolve after the last byte.  Turns out
this worked.

Thanks again for your help,
Jimmy Wylie
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.eros-os.org/pipermail/e-lang/attachments/20080929/d2430338/attachment.html 


More information about the e-lang mailing list