Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Do it yourself Webserver (Teil 4)

1 view
Skip to first unread message

Stefan Matthias Aust

unread,
Apr 16, 2006, 5:35:33 AM4/16/06
to
Angenommen, wir wollen eine Webanwendung schreiben, die nacheinander
zwei Zahlen einliest und die Summe anzeigt. Wie würde der Code dazu
aussehen?

Oder anders gefragt, warum kann der Code nicht so aussehen?

webPrint("Ergebnis",
webRead("Erste Zahl") + webRead("Zweite Zahl"));

Stattdessen müssen wir unsere (in diesem Beispiel sicherlich primitive)
Anwendungslogik zerreißen und dem zustandslosen HTTP-Protokoll und
ereignisgesteuerten Ablauf des Browsers unterwerfen:

- zeige ein Eingabeformular mit dem Prompt "Erste Zahl" an.
- reagiere auf die Eingabe der ersten Zahl und zeige jetzt ein
Eingabeformular mit dem Prompt "Zweite Zahl" an, merke dir
dabei die erste Zahl, z.B. als versteckte Eingabe in dem zweiten
Formular
- reagiere auf die Eingabe der zweiten Zahl und zeige jetzt
eine Seite mit dem Text "Ergebnis" und dem Ergebnis der Addition
der zweiten Zahl mit der ebenfalls versteckt übertragenen ersten
Zahl an.

Wir müssen die Formulare also jeweils so gestalten, dass sie den
zukünftigen Programmablauf mit berücksichtigen. Diese Zukunft eines
Programms bezeichnet man als continuation und Sprachen wie z.B. Scheme
kennen sie als direktes Sprachkonzept.

Könnten wir continuations in Java benutzen, könnten wir vielleicht
obiges Programm direkt implementieren. Dies (wenigstens zu simulieren)
soll das Ziel dieses Teils des Tutorials sein.

Java hat keine Continuations, auch keine Coroutinen (die kleinen
Schwestern von Continuations), aber Threads, die näherungsweise benutzt
werden können, indem wir sie explizit anhalten und später weiterlaufen
lassen.

Auf die URL /start hin wollen wir eine neue Continuation erzeugen, die
dann das obiges Programm ablaufen lässt. Die Continuation soll unter
einer einzigartigen ID abgelegt werden, damit wir sie bei jeder weiteren
Anfrage, die mit /continue eingeleitet werden soll, wiederfinden.

public class ContinuationWeblet extends Weblet {
private final Map<String, Continuation> continuations =
new HashMap<String, Continuation>();

public boolean matches(WebRequest request) {
return request.urlStartsWith("/start") ||
request.urlStartsWith("/continue");
}

public void handle(WebRequest request, WebResponse response)
throws IOException {
if (request.getUrl().startsWith("/start")) {
newContinuation().start(request, response);
} else if (request.getUrl().startsWith("/continue")) {
getContinuation(request).resume(request, response);
} else {
response.sendError("404 Not found", null);
}
}

private Continuation newContinuation() {
synchronized (continuations) {
String id;
do {
id = newId();
} while (continuations.containsKey(id));
Continuation cont = new Continuation(id);
continuations.put(id, cont);
return cont;
}
}

private String newId() {
...
}
...
}

Als ID nehmen wir am besten eine ausreichend lange Folge zufälliger
Zeichen. Die konkrete Implementation sei dem Leser überlassen.

Dies ist der Aufbau einer Continuation:

public class Continuation extends Thread {
private final String id;
private WebRequest request;
private WebResponse response;

Continuation(String id) {
this.id = id;
}

protected void init(WebRequest request, WebResponse response) {
this.request = request;
this.response = response;
}

public void start(WebRequest request, WebResponse response) {
init(request, response);
start();
...
}

public void resume(WebRequest request, WebResponse response) {
init(request, response);
...
}

public void run() {
...
}
}

Ich bin mir nicht sicher, ob eine Thread-Unterklasse die beste Idee ist,
aber irgendwie muss ich den Thread schließlich starten, laufenlassen und
dabei unterbrechen können. Dazu später mehr. WebRequest und WebResponse
werden jeweils übergeben und in Exemplarvariablen gespeichert, damit sie
in der run-Methode zur Verfügung stehen. (Seufz: Alles muss man in Java
selbst machen - auch closures...)

Zunächst möchte ich den Code zeigen, der eine Continuation wiederfindet:

public class ContinuationWeblet...
...
private Continuation getContinuation(WebRequest request) {
Continuation cont;
synchronized(continuations) {
cont = continuations.get(request.getParameter("id"));
}
if (cont == null) {
cont = NullContinuation;
}
return cont;
}

private static final Continuation NullContinuation =
new Continuation() {
public void resume(WebRequest request, WebResponse response) {
init(request, response);
merge(ERROR_TEMPLATE);
}

};

private static final String ERROR_TEMPLATE = ...
}

Wir benutzen hier das Null-Object-Pattern, das statt null ein spezielles
Objekt benutzt, um so eine Fallunterscheidung oder NullPointerException
in der eigentlichen Methode zu vermeiden und die Lesbarkeit zu erhöhen.

Der Fehlertext sagt sowas wie "hey, diese continuation gibt es nicht,
klicke auf /start um neu zu beginnen".

Wie man sieht, habe ich die merge-Methode in die Continuation-Klasse
verschoben. Wahrscheinlich sollte auch der Fehlertext dort stehen.

Die eigentliche Magie geschieht in der Continuation-Klasse, dort wo ich
die "..." eingefügt habe. Beginnen wir mit der run()-Methode:

class Continuation...
public void run() {
webPrint("Ergebnis",
webRead("Erste Zahl") + webRead("Zweite Zahl"));
}

private int webRead(String prompt) {
merge(
"<html><head><title>@prompt@</title></head>" +
"<body><h1>@prompt@</h1>" +
"<form method='post' action='@url@'>" +
"<input type='text' name='value' />" +
"<input type='submit' value='OK' />" +
"</form></body></html>",
"prompt", prompt, "url", url());
yieldControl();
return Integer.parseInt(request.getParameter("value"));
}

private void webPrint(String prompt) {
merge(
"<html><head><title>@prompt@</title></head>" +
"<body><h1>@prompt@</h1>" +
"<p>@result@</p>" +
"<p><a href='/start'>Restart</a></p>" +
"</body></html>",
"prompt", prompt, "result", Integer.toString(result));
yieldControl();
}

private String url() {
return "/continue?id=" + id;
}
}

Die Methode yieldControl() hält den Thread (und damit die Ausführung der
Continuation) an und lässt die zwischenzeitlich wartende start() bzw.
resume()-Methode weiterlaufen, auf dass die erstellte WebResponse
abgeschickt werden kann:

public class Continuation...
...
private final Condition yield = new Condition();
private final Condition wait = new Condition();
...
public void start...
...
start();
yield.await();
}

public void resume...
...
wait.signal();
yield.await();
}

private void yieldControl() {
yield.signal();
wait.await();
}
...
}

Was ist eine Condition? Ein Synchronisationspunkt zwischen zwei
Threads. Wahrscheinlich gibt es da auch eine fertige Klasse im JDK 1.5,
aber so war es für mich einfacher:

static class Condition {
private boolean b;

synchronized void signal() {
if (!b) {
b = true;
notify();
}
}

synchronized void await() {
while (!b) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
b = false;
}
}

Die Methode signal() setzt ein Flag. Mit await() kann ich in einem
anderen Thread auf dieses Flag warten. Danach wird das flag
zurückgesetzt, damit die Condition ein zweites Mal benutzt werden kann.

Schauen wir uns mit diesem Wissen nochmal die Continuation-Methoden an:

- Continuation#start() wird aus dem Thread des Handlers aufgerufen und
startet Continuation#run() als Continuation-Thread. Dieser läuft
sofort oder später los, wichtig ist nur, dass der Handler-Thread auf
ein "yield"-Signal wartet. Das wird die Continuation auslösen, wenn
die WebResponse fertig ist und vorerst unterbrochen werden soll.
- Continuation#run() läuft parallel zum wartenden Handler-Thread los
und führt das erste webRead() aus, welches yieldControl() aufruft.
- Continuation#yieldControl() sagt dem wartenden Handler-Thread, dass
er weitermachen kann und wartet selbst auf ein Signal, dass ein neuer
Handler-Thread schicken wird, wenn /continue aufgerufen wird.
- Während der Continuation-Thread also auf "wait" (besser wäre ja
continue, aber das ist ein Schlüsselwort in Java) wartet, wird
Continuation#resume() aus einem Handler-Thread aufgerufen, was
dem Continuation-Thread bescheid gibt, dass es weiter gehen kann
(mit neu untergeschobenem WebRequest und neuem WebResponse) und
wartet genau wie start() darauf, dass die Continuation wieder die
Kontrolle abgibt.

Wird das Ende von run() erreicht, stoppt leider die Continuation nicht,
sie hängt ewig - Künstlerpech.

Ich rekapituliere nochmal: Wenn wir im Browser auf /start zugreifen,
wird eine neue Continuation erzeugt und gestartet, während der
Handler-Prozess wartet. Die Continuation wird stückweise ausgeführt,
jedes Mal neu getriggert durch einen Request mit der URL /continue.
Verschiedene URLs sind unnötig. Die Continuation "weiss", wo es weiter geht.

Neben dem offensichtlichen Problem, welches sich dieses Rahmenwerk mit
vielen anderen einfachen Web-Rahmenwerken teilt - der Back-Button ist
tötlich für den Ablauf - hat das Rahmenwerk somit auch ein Problem mit
Reloads.

Doch gehen wir trotzdem noch einen Schritt weiter.

Eine WebComponent sei ein Objekt, das sich selbst auf einer WebPage
darstellen kann:

public abstract class WebComponent {
public abstract void renderOn(WebPage page);
}

public class WebPage {
...
public void render(String title, WebComponent component) {
print(
"<html>",
"<head><title>", title, "</title></head>",
"<body>", component, "</body>",
"</html>");
}
...
}

Die Methode print() ruft für WebComponent-Objekte renderOn() auf und für
alle anderen Objekte toString() und schreibt das Ergebnis in einen
StringBuffer, was mit getContent() abgefragt werden kann.

Ich taufe mein Rahmenwerk Landside (in Anlehnung an Avi Bryants
richtungsweisendes Seaside) und eine Landside-Continuation kann eine
WebPage anzeigen:

public abstract class Landside extends Continuation {
public Landside(String id) {
super(id);
}

public void renderPage(String title, WebComponent component) {
WebPage page = new WebPage(url());
do {
page.render(title, component);
page.emitOn(response);
yieldControl();
} while (page.doAction(request));
}
}

Das doAction() in der letzten Zeile erkläre ich gleich. Eine Seite
darstellen heißt ansonsten, die Komponente in HTML zu verwandeln
("render") und dann in die WebResponse zu schreiben ("emit"). Danach
wartet das Rahmenwerk auf eine Reaktion des Benutzers und beginnt ggf.
von vorn.

Zunächst möchte ich die Implementierung einer beispielhaften
WebComponent zeigen: Einen Zähler.

class Counter extends WebComponent {
private int value;

public void increment() {
value += 1;
}

public void decrement() {
value -= 1;
}

public void renderOn(WebPage page) {
page.print(
"<h1>", value, "</h1>",
"<p>",
page.button("++", action("increment")), " ",
page.button("--", action("decrement")),
"</p>");
}

WebAction action(String name) {
return new WebAction(this, name);
}
}

Ein Zähler hat offensichtlich einen Wert, den man durch den Aufruf
zweier Methoden erhöhen oder erniedrigen kann. Die Methode renderOn()
malt die Komponente. Spannend ist hier der Aufruf von WebPage#button().
Damit registriere ich einen Link, der an die angegebene WebAction
gebunden ist. Was eine WebAction ist? Das hier:

static class WebAction {
private final WebComponent component;
private final Method method;

WebAction(WebComponent component, String name) {
this.component = component;
try {
this.method = component.getClass().getMethod(name);
} catch (NoSuchMethodException e) {
throw new Error(e);
}
}

void invoke() {
try {
method.invoke(component);
} catch (Exception e) {
throw new Error(e);
}
}
}

Der manifestierte Schmerz einer nicht-dynamischen Programmiersprache
ohne Closures, in Code gegossen...

Was macht eine WebPage mit einer WebAction? In erster Linie sich
merken. Und eine einzigartige URL erzeugen, die nach einem
yieldControl() von doAction() wieder erkannt wird und dann die Aktion
aufruft. Hier ist der entsprechende Code:

class WebPage ...
private String url;
private Map<String, WebAction> actions =
new HashMap<String, WebAction>();
...

WebPage(String url) {
this.url = url;
}

...

String button(String label, WebAction action) {
String id = Integer.toString(actions.size());
actions.put(id, action);
return "<a href='" + url + "?a=" + id + "'>" + label + "</a>";
}

boolean doAction(String id) {
WebAction action = actions.get(id);
actions.clear();
if (action != null) {
action.invoke();
return true;
}
return false;
}
}

Das sieht zwar alles recht umständlich aus, aber schauen wir uns nochmal
die Counter-Klasse an: Hier haben wir eine Exemplarvariable, zwei
Methoden zum Ändern der Variablen und eine kleine Methode, die das ganze
anzeigt. Das ist trivial und insbesondere sind alle Scheußlichkeiten von
HTTP-Requests und Responses verborgen.

Fehlt nur noch:

class CounterExample extends Landside {
public void run() {
renderPage("Counter Example", new Counter());
}
}

Wenn ich nichts vergessen habe, funktioniert das jetzt, wenn wir das
ContinuationWeblet aus dem dritten Teil auf die CounterExample
-Continuation umstellen und den WebServer starten.

Da dieses Rahmenwerk komponentenbasiert ist, kann man ohne große Mühe
auch 10 Zähler anzeigen:

class Container extends WebComponent {
private List<WebComponent> children = new ArrayList<WebComponent>();

public void add(WebComponent component) {
children.add(component);
}

public void renderOn(WebPage page) {
page.print(children);
}
}

Ich habe dabei die print-Methode erweitert, sodass sie automatisch
Collections expandiert:

} else if (a instanceof List) {
for (Object o : (List) a) {
print(o);
}
...

Dies ist die neue run()-Methode:

public void run() {
Container c = new Container();
for (int i = 0; i < 10; i++) {
c.add(new Counter());
}
renderPage("Counter Example", c);
}

Noch nicht beeindruckt? Wie wäre es hiermit?

Zuerst eine kleine Änderung am Counter:

class Counter...
...
public void increment() {
if (value == 3) {
messageDialog("Maximmum erreicht!");
return;
}
value += 1;
}
...
}

Ich will dem Benutzer einen modalen (!) Dialog anzeigen, den er
bestätigen muss, bevor er weiterzählen darf. Und größer als 3 ist aus
Sicherheitsgründen (zu große Zahlen könnten das Gehirn aufgrund zu
starken Nachdenkens irreparabel schädigen) nicht erlaubt.

Den Dialog leite ich als eigene Komponente von WebComponent ab:

class Dialog extends WebComponent {
private final String message;

Dialog(String message) {
this.message = message;
}

public void close() {
stack.pop();
}

public void renderOn(WebPage page) {
page.print(
"<div style='border:3px solid #999;padding:2em'>",
"<p>", message, "</p>",
"<p>", page.button("OK", action("close")), "</p>",
"</div>");
}
}

Die Methode action() habe ich nach WebComponent verschoben. Dort
definiere ich dann auch messageDialog():

class WebComponent...
protected WebComponentStack stack;
...
protected void messageDialog(String message) {
stack.push(new Dialog(message));
}
}

Der WebComponentStack dient dazu, dass sich Komponenten überlagen
können. Seaside hat's hier einfacher, da Exemplare einfach dynamisch mit
#become: ausgetauscht werden können. Ich muss das hier implementieren:

class WebComponentStack extends WebComponent {
private final LinkedList<WebComponent> stack =
new LinkedList<WebComponent>();

WebComponentStack(WebComponent component) {
push(component);
}

public void push(WebComponent component) {
component.stack = this;
stack.addLast(component);
}

public void pop() {
stack.removeLast().stack = null;
}

public void renderOn(WebPage page) {
stack.getLast().renderOn(page);
}
}

Und ich muss mein Programm jetzt so initialisieren:

Container c = new Container();
for (int i = 0; i < 10; i++) {
c.add(new WebComponentStack(new Counter()));
}
renderPage("Counter Example", c);

Nach einem Neustart des Servers habe ich jetzt unabhängige Komponenten
jeweils mit eigenem Kontrollfluss - eventgesteuert, wie man ein UI bauen
würde.

--
Stefan Matthias Aust

Message has been deleted
Message has been deleted

Stefan Matthias Aust

unread,
Apr 20, 2006, 6:06:09 AM4/20/06
to
Stefan Ram schrieb:

> Stefan Matthias Aust <nob...@3plus4.de> writes:
>> Oder anders gefragt, warum kann der Code nicht so aussehen?
>> webPrint("Ergebnis",
>> webRead("Erste Zahl") + webRead("Zweite Zahl"));
>
> Ich kenne mich mit Web-Rahmen nicht aus.

Sowas hält unsereins doch nicht ab, oder? :)

> Deswegen mußte ich mir jetzt schnell etwas ausdenken.
> Also hier mein primitiver Rahmen. [...]

Du baust, wenn ich deinen Kode richtig entziffere, einen
Zustandsautomaten (ich deutsche das für dich extra mal ein) und
implementierst damit das, was die Continuation ausmacht, explizit
selbst. Genau das soll ja nicht passieren, d.h.

webPrint("Ergebnis",
webRead("Erste Zahl") + webRead("Zweite Zahl"));

soll unverändert so bleiben und gesucht ist einzig eine geschickte
Implementierung für webPrint und webRead.

> Mit continuations kenne ich mich auch nicht aus, aber diese
> entsprechen vermutlich dem, was bei mir in den
> Maschinenvariablen Machine#env und Machine#pc steht.

Das ist korrekt. Eine weitere wichtige Eigenschaft ist, dass du
mehrfach die Ausführung einer Maschine an der selben Stelle fortsetzen
kannst, aber ich denke, das funktioniert mit deiner Implementierung.

--
Stefan Matthias Aust // Ergo bibamus, ne sitiamus, vas repleamus!

Stefan Matthias Aust

unread,
Apr 20, 2006, 7:12:21 AM4/20/06
to
Nachtrag: In JavaScript geht das alles recht elegant.

Gegeben ist wieder diese Funktion:

function run() {


webPrint("Ergebnis", webRead("Erste Zahl") + webRead("Zweite Zahl"))
}

Die Implementierung der beiden Funktionen ist geradeheraus:

function webRead(prompt) {
emit("<html><head><title>", prompt, ...
"<form action='", url, ...
"<input name='v' ...)
yieldControl()
return req.getParameter("v")
}

function webPrint(prompt, result) {
emit("<html>... ", result, ...)
}

Die Funktion emit() schenke ich mir, sie macht aus Strings und Werten
einen String und schreibt ihn per

res.contentType = "text/html"
res.writer.println(result)

in die Response.

Spannender ist die Funktion yieldControl. Sie erzeugt und speichert eine
neue Continuation, die dann später beim nächsten Request fortgesetzt
wird. Danach beendet sich die Funktion, indem eine zuvor gespeicherte
exit-Continutation fortgesetzt wird. Wie req und res speichere ich
beide Continuations in globalen Variablen:

var exit
var cont
function yieldControl() {
cont = new Continuation()
exit()
}

Hier wird die exit-Continuation angelegt:

function doit() {
exit = new Continuation()
if (cont != null) {
cont()
} else {
run()
}
}

Damit ich das jetzt aus Java heraus aufrufen kann, braucht es noch ein
kleines Servlet (ich werde nicht müde, hinzuweisen, dass die Java-Seite
tatsächlich mehr Zeilen hat als der JavaScript-Code):

class ContinuationServlet extends HttpServlet {
private ScriptEngine engine;
private Map<String, Object> continuations;
private int nextId;

void init(...) {
engine = new ScriptManager().getEngineByName("JavaScript");
engine.eval(/* hier den obigen JavaScript-Code lesen */);
continuations = new HashMap<String, Object>();
}

void doGet(....) {
String id = /* id from URL extrahieren */

Object continuation;
synchronized (continuations) {
continuation = continuations.get(id);
id = Integer.toString(++nextId);
}

Bindings b = engine.getBindings(ScriptContext.ENGINE_SCOPE);
b.put("req", request);
b.put("res", response);
b.put("cont", continuation);
b.put("id", id);
engine.eval("doit()", b);
synchronized (continuations) {
continuations.put(
id,
engine.getBindings(ScriptContext.ENGINE_SCOPE).get("cont"));
}
}
}

Wenn man HttpSessions benutzen würde, müsste das noch einfacher gehen,
ich fand aber bei meinem Test auf die Schnelle nicht, wie ich das in
Jetty, das ich direkt ohne web.xml starte, realisiere.

Ich bin mir nicht sicher, ob die Engine wohl thread-safe ist. Außerdem
räume ich meine Continuations nie auf, man will wahrscheinlich nicht
alle für eine unbegrenzte Reise in die Vergangenheit aufbewahren,
sondern nur die letzten 10 oder nur für X Minuten oder so.

Timo Stamm

unread,
Apr 20, 2006, 7:24:51 AM4/20/06
to
Stefan Matthias Aust schrieb:

> Angenommen, wir wollen eine Webanwendung schreiben, die nacheinander
> zwei Zahlen einliest und die Summe anzeigt. Wie würde der Code dazu
> aussehen?
>
> Oder anders gefragt, warum kann der Code nicht so aussehen?
>
> webPrint("Ergebnis",
> webRead("Erste Zahl") + webRead("Zweite Zahl"));

Weil man dafür Threads braucht, und die sind ja teuer und das skaliert
nicht und es fördert einen prozeduralen Stil anstatt einem
objektorientierten Vorgehen und überhaupt geht das ja auch mit einer
State Machine.

Zumindest sind das die Argumente die auf meinen Vorschlag in der
Wicket-user Mailingliste kamen. Ich schätze man wollte sich Arbeit vom
Hals halten, was ich gut nachvollziehen kann :)

Deine Ausführungen fand ich sehr gut. Ich hoffe ich habe tatsächlich mal
die Zeit eine Continuations-Implementation für Wicket zu machen. Der
grösste Aufwand wird wohl sein das vernünftig und ohne Änderungen am
Kern umzusetzen, nicht die Continuations-Engine selbst. Trotzdem ist
dein Artikel da schon mal eine grosse Hilfe.

Wenn es dich interessiert, hier mein Vorschlag wie Continuations in
Wicket aussehen könnten:
http://sourceforge.net/mailarchive/message.php?msg_id=13995847


Timo

PS: Ich fand es sehr interessant zu sehen dass du jetzt doch HTML in
Java Strings schreibst ;)

Stefan Matthias Aust

unread,
Apr 20, 2006, 12:00:26 PM4/20/06
to
Timo Stamm schrieb:

>> webPrint("Ergebnis",
>> webRead("Erste Zahl") + webRead("Zweite Zahl"));
>

> Weil man dafür Threads braucht [...]

Braucht man nicht ... siehe mein JavaScript-Beispiel.

> und die sind ja teuer und das skaliert
> nicht und es fördert einen prozeduralen Stil anstatt einem
> objektorientierten Vorgehen

Sehe ich nicht so. Es fördert im Gegenteil funktionale Programmierung
und hält Code zusammen, der zusammen gehört.

> und überhaupt geht das ja auch mit einer State Machine.

Nur viel umständlicher. Vergleiche Stefan Rams Beispiel...

> Wenn es dich interessiert, hier mein Vorschlag wie Continuations in
> Wicket aussehen könnten:
> http://sourceforge.net/mailarchive/message.php?msg_id=13995847

Ich habe das kurz überflogen und muss leider sagen, in der Diskussion
weiss keiner, worum es eigentlich bei IMHO wirklich Continuations geht.
Das Argument mit den Threads trifft nur auf Java zu, was keine
continuations oder co-routinen kennt. Sprachen wie Erlang oder Io
(allgemein alles, was die Idee von Actor, nämliche aktive Objekte,
aufgreift), die auf viele Threads oder Prozesse optimiert sind, haben
keine Probleme mit 10.000 oder 100.000 (quasi-)parallelen Prozessen.

> PS: Ich fand es sehr interessant zu sehen dass du jetzt doch HTML in
> Java Strings schreibst ;)

Ist halt am einfachsten hier für meine Beispiele :)

Stefan Matthias Aust

unread,
Apr 20, 2006, 12:01:22 PM4/20/06
to
Stefan Ram schrieb:
> r...@zedat.fu-berlin.de (Stefan Ram) writes:
>> GET server?machine=AB65E5C0-CE48-11DA-A6BC-00A0CC554CB0&value=2
>
> Interessant wird es dann, wenn man versucht auch noch »das
> Richtige« zu tun, wenn der Benutzer mit der »Zurück«-Taste
> seines Klienten zurückgeht und ein altes Formular noch einmal
> abschickt oder so etwas. Will er mit »Zurück« zur Bestellseite
> alle bisherigen Bestellungen ungeschehen machen (»undo«) oder
> nur noch eine weiter Bestellung hinzufügen?

Das ist in der Tat ein Problem, weil continuations "zu gut" sind.

Message has been deleted

Timo Stamm

unread,
Apr 20, 2006, 12:23:27 PM4/20/06
to
Stefan Matthias Aust schrieb:

> Timo Stamm schrieb:
>
>>> webPrint("Ergebnis",
>>> webRead("Erste Zahl") + webRead("Zweite Zahl"));
>>
>> Weil man dafür Threads braucht [...]
>
> Braucht man nicht ... siehe mein JavaScript-Beispiel.
>
> > und die sind ja teuer und das skaliert
>> nicht und es fördert einen prozeduralen Stil anstatt einem
>> objektorientierten Vorgehen
>
> Sehe ich nicht so. Es fördert im Gegenteil funktionale Programmierung
> und hält Code zusammen, der zusammen gehört.
> > und überhaupt geht das ja auch mit einer State Machine.
>
> Nur viel umständlicher. Vergleiche Stefan Rams Beispiel...

Ganz meine Meinung. Die Gegenargumente die ich aufgezählt habe stammen
nicht von mir, sondern von den Wicket-committern.


>> Wenn es dich interessiert, hier mein Vorschlag wie Continuations in
>> Wicket aussehen könnten:
>> http://sourceforge.net/mailarchive/message.php?msg_id=13995847
>
> Ich habe das kurz überflogen und muss leider sagen, in der Diskussion
> weiss keiner, worum es eigentlich bei IMHO wirklich Continuations geht.

Das kommt mir auch so vor. Aber ich kann die Leute ja nicht zur
Erkenntnis zwingen, das führt nur zu flame wars. Muss ich halt selber
schreiben.


> Das Argument mit den Threads trifft nur auf Java zu, was keine
> continuations oder co-routinen kennt. Sprachen wie Erlang oder Io
> (allgemein alles, was die Idee von Actor, nämliche aktive Objekte,
> aufgreift), die auf viele Threads oder Prozesse optimiert sind, haben
> keine Probleme mit 10.000 oder 100.000 (quasi-)parallelen Prozessen.

Ich will aber Continuations in Wicket, also Java.

Aber selbst wenn Continuations nur mit Threads möglich sind ist mir das
egal, denn bei einer Anwendung mit wenigen dutzend Usern ist der Nutzen
bei komplexen Abläufen mit viel Interaktion hoch.


Timo

Stefan Matthias Aust

unread,
Apr 20, 2006, 12:24:04 PM4/20/06
to
Stefan Ram schrieb:

> Es ist natürlich verdienstvoll, daß Du es überhaupt
> versucht hast, aber Du sahst ja auch, daß Java Dir diese
> Implementation nicht gerade einfach gemacht hat.

In der Tat.

> Da fragte ich mich, ob solch ein expliziter Interpretierer
> dann nicht das »kleinere Übel« sei. Seine einzelnen Operationen
> können dann schließlich wiederum in Java geschrieben werden,
> also Gebrauch von allen Möglichkeiten der Sprache Java machen.

Das würde ich sagen. Allerdings nicht unbedingt in der Form, die du
präsentiert hast, sondern z.B. in Form eines JavaScript-Interpreters.

> Zudem können die Programm für die simulierte Maschine auch zur
> Laufzeit manipuliert werden, während Java-Code ja erst einmal
> statisch ist.

Das dynamische manipulieren empfände ich als Vorteil, den mein Ziel ist
eigentlich die Entwicklungsumgebung im Web, wie sie Seaside bietet.

Mein nächster Versuch ist daher, einen Interpreter zu bauen, der
Continuations kann, weil ich das glaube ich immer noch nicht 100%ig
verstanden habe :(

Oder ich schaue mir erstmal
http://download.plt-scheme.org/doc/301/html/web-server/ an...

Stefan Matthias Aust

unread,
Apr 20, 2006, 12:29:16 PM4/20/06
to
Timo Stamm schrieb:

> Aber selbst wenn Continuations nur mit Threads möglich sind ist mir das
> egal, denn bei einer Anwendung mit wenigen dutzend Usern ist der Nutzen
> bei komplexen Abläufen mit viel Interaktion hoch.

Leider ist es IMHO noch nicht einmal mit Threads möglich, weil du
Threads klonen können müstest, um den Back-Button richtig zu
unterstützen. Es muss möglich sein, eine Continuation mehr als einmal
fortzusetzen.

Wenn du partu bei Java bleiben willst, wäre vielleicht - wenn es dann
zumindest eine häßliche Lösung gäbe - ein spzieller post prozessor in
Form eines ClassLoaders ein Weg, den Code automatisch zu tranformieren.

Ich meine RIFE geht so vor, allerdings meine ich ebenfalls (ohne das
genauer angeschaut zu haben), dass sie dort keine echten Continuations
haben.

Wenn man wenigstens in Java resume/retry-bare Exceptions hätte...

Frank Buss

unread,
Apr 20, 2006, 1:23:44 PM4/20/06
to
Stefan Matthias Aust wrote:

> Das dynamische manipulieren empfände ich als Vorteil, den mein Ziel ist
> eigentlich die Entwicklungsumgebung im Web, wie sie Seaside bietet.

Ich habe mir eben mal das Video auf http://seaside.st/ angesehen (habe zwar
nichts vom Portugiesisch verstanden, aber die Bildchen waren ausreichend)
und ich sehe nicht, warum es ein Vorteil ist, den Klassenbrowser als HTML
zu haben und dort ohne Syntax-Highlighting o.ä. Code eintippen zu können.
Das kann doch das Smalltalk-System selbst viel besser?

Das Framework selbst sieht so auf den ersten Blick recht gut programmierbar
aus, ähnlich wie UCW (muß ich wirklich mal ausprobieren), mit
Continuations. Scheint auch recht einfach zu sein, zu Aktionen eigene
Webseiten zu entwerfen.

--
Frank Buss, f...@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de

Christoph Jerolimov

unread,
Apr 21, 2006, 3:55:32 AM4/21/06
to
Stefan Matthias Aust schrieb:

> Timo Stamm schrieb:
>
>> Aber selbst wenn Continuations nur mit Threads möglich sind ist mir
>> das egal, denn bei einer Anwendung mit wenigen dutzend Usern ist der
>> Nutzen bei komplexen Abläufen mit viel Interaktion hoch.
>
>
> Leider ist es IMHO noch nicht einmal mit Threads möglich, weil du
> Threads klonen können müstest, um den Back-Button richtig zu
> unterstützen. Es muss möglich sein, eine Continuation mehr als einmal
> fortzusetzen.

Mal ganz blöde gefragt: Würde es nicht reichen sich einfach jeden
Zustand zu merken? Also bei HTTP jeden Request zwischen zu speichern und
dann bei allen Aktionen eine eindeutige ID vorranzustellen?

Du willst bei "diesen Continuation" -- hab den Begriff eigentlich immer
nur hier in der NG von dir gelesen, vermutlich fehlt mir da eine
schlüssige Definition -- also einfach nur zwischen Zwei Funktionen wie
"webRead() + webRead()" eine weitere Response haben, oder? *selber noch
ein wenig drüber Nachdenk*

Gruß Christoph

Stefan Matthias Aust

unread,
Apr 21, 2006, 4:53:07 AM4/21/06
to
Christoph Jerolimov schrieb:

> Mal ganz blöde gefragt: Würde es nicht reichen sich einfach jeden
> Zustand zu merken?

Das funktioniert IMHO in Java nicht, weil ich mir nicht den Zustand des
Systemstacks merken kann, was ich müsste, um das Programm genau an
dieser Stelle (mehrfach) fortsetzen zu können.

Der Trick bei diesem simplen Beispiel mit dem "+" ist ja, dass das
Programm quasi in der "+"-Operation anhält, und dort mehrfach mit
verschiedenen zweiten Operanden - wenn man im Browser nach dem Ergebnis
immer wieder den Back-Buttond drückt - addiert wird.

> Du willst bei "diesen Continuation" -- hab den Begriff eigentlich immer
> nur hier in der NG von dir gelesen, vermutlich fehlt mir da eine
> schlüssige Definition

Definition: Eine Continuation ist eine (virtuelle) Funktion, die den
Rest der Ausführung eines Programms repräsentiert. Sie repräsentiert
damit einen Momentaufnahme der aktuellen Ausführungsumgebung, häufig
eines Stacks.

Siehe auch http://en.wikipedia.org/wiki/Continuation für mehr
Informationen. Es gibt zu dem Thema aber einiges an Literatur:
http://library.readscheme.org/page6.html ;)

Mir hat der Artikel "Teach yourself Scheme in Fixnum Days" und dort der
Abschnitt über "Amb" geholfen, Continuations zu verstehen.

> -- also einfach nur zwischen Zwei Funktionen wie
> "webRead() + webRead()" eine weitere Response haben, oder?

Ja.

PLT-Scheme benutzt da vielleicht die besseren Namen. Dort gibt es eine
"send/suspend"-Funktion (der Name enthält ein "/", da ist nichts
besonderes dabei), die eine Funktion übergeben bekomt, die wiederum eine
continue-URL übergeben bekommt und eine web-response erzeugt und wo
send/suspend dann selbst einen web-request liefert. Per Konvention
startet eine PLT-Scheme-Webanwendung mit einer Funktion "start", die den
initialen Request bekommt und eine web-response liefert soll.

Übersetzt in Scala könnte das so aussehen:

abstract class Servlet {
def start(req: Request): Response
def sendAndSuspend(f: String => Response): Request = {
...
}
}

class OnePage extends Servlet {
def start(req: Request): Response = {
Response(<html>...<h1>Hello</h1>...</html>)
}
}

class TwoPages extends Servlet {
def start(req: Request): Response = {
val req = sendAndSuspend(kUrl =>
Response(<html>...
<a href="{kUrl + "?link=1"}">Link 1</a>
<a href="{kUrl + "?link=2"}">Link 2</a>
...</html>))
Response(<html>...
<p>You chose Link {req.parameter("link")}</p>
...</html>)
}
}

Und das klassische Additionsbeispiel könnte so aussehen:

class AddEx extends Servlet {
def start(req: Request): Response = {
webPrint("Ergebnis", webRead("Eins") + webRead("Zwei"))
}

private def webRead(prompt: String): Int = {
val req = sendAndSuspend(kUrl =>
Response(<html>...<form action="{kUrl}"><input name="v">...))
req.parameter("v").toInt
}

private def webPrint(prompt: String, value: Int) = {
Response(<html>...)
}
}

Leider ist es auch in Scala nicht möglich, sendAndSuspend zu
implementieren...

Was man machen müsste, wäre einen Snapshot vom aktuellen
Ausführungsstack und Zeiger auf die nächste auszuführende Anweisung
derart anzulegen, sodass man später das Programm ab diesem Zeitpunkt
weiter laufen lassen kann.

Dann muss man das Programm hier abbrechen, indem man einen zuvor
gesetzten Snapshot fortsetzt, der die erstellte Response jetzt an den
Browser übergibt und dann die Kontrolle bis zum nächsten Request
komplett abgibt.

Stefan Matthias Aust

unread,
Apr 21, 2006, 5:19:49 AM4/21/06
to
Frank Buss schrieb:

> Ich habe mir eben mal das Video auf http://seaside.st/ angesehen (habe zwar
> nichts vom Portugiesisch verstanden, aber die Bildchen waren ausreichend)
> und ich sehe nicht, warum es ein Vorteil ist, den Klassenbrowser als HTML
> zu haben und dort ohne Syntax-Highlighting o.ä. Code eintippen zu können.

Syntaxhighlighting hast du sonst auch nicht... Ein Vorteil ist, dass du
das System remote installieren und administrieren kannst. Die Werkzeuge
könnte man IMHO noch deutlich verbessern... sogar remote.

> Das kann doch das Smalltalk-System selbst viel besser?

Ein bisschen, aber dort hat man sich Jahre lang auf dem Stand der späten
80er Jahre ausgeruht und inzwischen bieten Eclipse und Co ähnliche oder
bessere Möglichkeiten.

Entscheidend ist ... grummel, jetzt scheint die brasiliansche Site down
zu sein... jedoch, dass man während der Entwicklung direkt im Browser
Zugriff auf all diese netten Werkzeuge hat, angefangen von der
Möglichkeit, mal die Komponenten und das HTML selbst zu sehen, über den
Profiler bis hin zum Inspector für das laufende Programm.

> Das Framework selbst sieht so auf den ersten Blick recht gut programmierbar
> aus, ähnlich wie UCW (muß ich wirklich mal ausprobieren), mit
> Continuations. Scheint auch recht einfach zu sein, zu Aktionen eigene
> Webseiten zu entwerfen.

Ja, die benutzen das send/suspend/dispatch-Pattern, was auch PLT-Scheme
benutzt. Ich weiss nicht, wer zuerst war. 2002 gibt es Paper zum
"Continue-Server" und 2003, wie man ihn mit obigem Pattern neu gebaut
hat. Ich glaube, Seaside ist 2002 entstanden. Da gibt es jedenfalls
einen Talk auf einer Ruby-Konferenz zu Seaside.

Frank Buss

unread,
Apr 21, 2006, 5:46:11 AM4/21/06
to
Stefan Matthias Aust wrote:

> Entscheidend ist ... grummel, jetzt scheint die brasiliansche Site down
> zu sein... jedoch, dass man während der Entwicklung direkt im Browser
> Zugriff auf all diese netten Werkzeuge hat, angefangen von der
> Möglichkeit, mal die Komponenten und das HTML selbst zu sehen, über den
> Profiler bis hin zum Inspector für das laufende Programm.

Vielleicht hast du Recht. Eine typische Lisp-Lösung sähe z.B. so aus: Auf
dem Server läuft ein Lisp-Prozess, der einen Webserver beinhaltet und eine
REPL-Kommandozeile, die z.B. per http://www.cliki.net/detachtty gestartet
wurde und auf die man per SSH mit http://www.cliki.net/SLIME von seinem
lokalen Emacs drauf zugreift. Emacs habe ich selbst noch nicht verwendet,
aber man könnte dort auch die Tastaturbelegung so umdefinieren, daß die mit
"normalen" Windows Menschen verträglich ist. Man kann dann jeweils
Quelltext öffnen, editieren und per SLIME ins laufende System kompilieren
und debuggen. Soweit ist das ungefähr gleich, wie wenn man in Squeak
editiert und es im Browser anzeigt.

Ich sehe aber den Nachteil des Medienbruchs, wenn man es nur in der IDE
editieren könnte: Squeak (und Emacs) bieten eine andere Sichtweise auf das
System, als man es im Browser sieht, also z.B. muß man bei einer Webseite
erst den dazugehörigen Quelltext suchen, wobei bei Seaside das mit einem
Klick auf den Quelltextbutton der gerade dargestellten Seite möglich ist
(denke ich). Ist also in der praktischen Anwendung wahrscheinlich gar nicht
so schlecht.

Fazit: man baut Zope nach, also eine Webanwendung, mit der man
Webanwendungen bauen kann :-)

In Java sähe das dann z.B. so aus, daß man z.B. einen
JavaScript-Interpreter einsetzt und per Webinterface die Scripts und
dazugehörigen Templates anlegen und ändern kann. Ideal wäre dann noch ein
Editor als Browser-Plugin, der eine Verbindung zum Java-Server aufnimmt und
beim editieren von Quelltext z.B. auto-completion bereitstellt. Oder ganz
visionär: Man baut in Eclipse einen Webeditor, der in integrierten
Textfeldern die Editor-Funktionen von Eclipse bereitstellt. Da bekäme man
dann viel von der Projektverwaltung usw. für die Webanwendung zum
webanwendungsbauen geschenkt.

Stefan Matthias Aust

unread,
Apr 21, 2006, 6:27:34 AM4/21/06
to
Frank Buss schrieb:

> Vielleicht hast du Recht. Eine typische Lisp-Lösung sähe z.B. so aus: Auf
> dem Server läuft ein Lisp-Prozess, der einen Webserver beinhaltet und eine
> REPL-Kommandozeile, die z.B. per http://www.cliki.net/detachtty gestartet
> wurde und auf die man per SSH mit http://www.cliki.net/SLIME von seinem
> lokalen Emacs drauf zugreift.

Tja, in PHP oder auch (Ruby on) Rails sähe es so aus, dass man einfach
den Quelltext ändert und das System bei jedem Request ja komplett und
immer alles neu lädt und quasi neu startet und dadurch ebenfalls die
Illusion der direkten Änderbarkeit bietet. Nervig dabei ist aber, dass
man nicht direkt eine Methode debuggen und ändern kann *während* die
Anwendung läuft. PHP und Rails gleichen das dadurch aus, dass wirklich
alles, was persistent sein soll, in die Datenbank wandert. Ist aber
IMHO unschön.

> Ich sehe aber den Nachteil des Medienbruchs, wenn man es nur in der IDE
> editieren könnte: Squeak (und Emacs) bieten eine andere Sichtweise auf das
> System, als man es im Browser sieht

Muss nicht so sein.

Ich würde mich jetzt sogar hinstellen und behaupten, du kannst einen
Webmacs in JavaScript bauen, jedenfalls eine Näherung, sodass der
Emacs-Anfänger keinen großen Unterschied sieht. Scheme-Interpreter in
JavaScript gibt es jedenfalls :)

Nein, die Herausforderung wäre schnelles Syntaxhighlighting. Das normale
<textarea> ist ja ungefähr so komfortabel wie notepad.

Man müsste also stattdessen das benutzen, was Mozilla Midas nennt und
Microsoft mit dem contenteditable-Attribut realisiert. Dann mit einem
Listener jede Änderung des Dokuments erfahren, mit regulären Ausdrücken
Regionen finden, dann dort span-Elemente mit der entsprechenden
CSS-Klasse einfügen und alte span-Elemente entfernen. Und das alles mit
umständlichen DOM-Befehlen.

Das scheint aber tatsächlich zu gehen (falls die das so machen):
http://demo.aboutedit.com. Wow, ich bin beeindruckt.

> Fazit: man baut Zope nach, also eine Webanwendung, mit der man
> Webanwendungen bauen kann :-)

Jein. Zope ist ja eher ein CMS. Man baut eigentlich eine IDE.

> In Java sähe das dann z.B. so aus, daß man z.B. einen
> JavaScript-Interpreter einsetzt und per Webinterface die Scripts und
> dazugehörigen Templates anlegen und ändern kann.

Z.B. Helma macht das so - Helma ist quasi sowas wie Zope für Java. Nur
hat Helma AFAIK keine eingebaute IDE, diese Idee hatten die Autoren
nicht oder sie war ihnen nicht so wichtig.

> Ideal wäre dann noch ein
> Editor als Browser-Plugin, der eine Verbindung zum Java-Server aufnimmt und
> beim editieren von Quelltext z.B. auto-completion bereitstellt.

Ich bin überzeugt, sowas kann man bauen.

> visionär: Man baut in Eclipse einen Webeditor, der in integrierten
> Textfeldern die Editor-Funktionen von Eclipse bereitstellt. Da bekäme man
> dann viel von der Projektverwaltung usw. für die Webanwendung zum
> webanwendungsbauen geschenkt.

Ah, du meist wie bei Seaside, was ja auch nur eine Hülle um die "echten"
Entwicklungstools darstellt und diese nicht nochmal neu baut? Durchaus
nett... aber vielleicht doch recht aufwendig :)

Frank Buss

unread,
Apr 21, 2006, 6:36:23 AM4/21/06
to
Stefan Matthias Aust wrote:

> Ah, du meist wie bei Seaside, was ja auch nur eine Hülle um die "echten"
> Entwicklungstools darstellt und diese nicht nochmal neu baut? Durchaus
> nett... aber vielleicht doch recht aufwendig :)

ja, so ähnlich: Statt die IDE in HTML nachzubauen dachte ich daran, HTML in
der IDE nachzubauen: Also daß Eclipse die Webanwendung ausführt und die
HTML-Seiten anzeigen kann, deren Templates und zugehörige Aktionen
verwaltet und bei Bedarf direkt einen Quelltexteditor zum passenden Kontext
aufruft. Das dürfte eigentlich nicht so aufwendig sein und u.U. sogar
einfacher, als der umgekehrte Weg mit einem reinen HTML-Browser.

Timo Stamm

unread,
Apr 21, 2006, 6:50:37 AM4/21/06
to
Frank Buss schrieb:

> Statt die IDE in HTML nachzubauen dachte ich daran, HTML in
> der IDE nachzubauen: Also daß Eclipse die Webanwendung ausführt und die
> HTML-Seiten anzeigen kann, deren Templates und zugehörige Aktionen
> verwaltet und bei Bedarf direkt einen Quelltexteditor zum passenden Kontext
> aufruft. Das dürfte eigentlich nicht so aufwendig sein und u.U. sogar
> einfacher, als der umgekehrte Weg mit einem reinen HTML-Browser.

Wenn ich dich richtig verstehe ist das eine ziemlich ähnliche Idee wie
die von Wolfgang Schmidetzki, Eclipse als CMS Autorenoberfläche zu benutzen:

http://vowe.net/archives/005723.html


Timo

Message has been deleted

Stefan Matthias Aust

unread,
Apr 22, 2006, 10:53:04 AM4/22/06
to
Frank Buss schrieb:

> ja, so ähnlich: Statt die IDE in HTML nachzubauen dachte ich daran, HTML in
> der IDE nachzubauen: Also daß Eclipse die Webanwendung ausführt und die
> HTML-Seiten anzeigen kann, deren Templates und zugehörige Aktionen
> verwaltet und bei Bedarf direkt einen Quelltexteditor zum passenden Kontext
> aufruft.

Verstehe. Aber läuft das nicht entweder auf einen eingebetteten IE (mit
dem Nachteil, das man nicht auf einem richtigen Browser wie Firefox oder
Safari entwickeln kann) oder gar den Nachbau eines Webbrowsers hinaus?

Stefan Matthias Aust

unread,
Apr 22, 2006, 11:22:19 AM4/22/06
to
Stefan Ram schrieb:

> Nach dem, was ich gestern über die Fortsetzungen bei den
> Aktoren von Hewitt gelesen habe, ist es zunächst einmal eine
> Art von Funktion. Dabei wird jedem Aktor eine Fortsetzung
> übergeben, an die er seine Ergebnisse schicken kann oder soll.

So verstehe ich das auch.

> Die Aktoren kehren aber -- im Gegensatz zu Methoden nie zum
> Aufrufer zurück.

Das ist jetzt Actor-spezifisch aber nicht typisch für continuations im
Sinne von Scheme. Dort bezeichnet eine continuation eben die Zukunft
eines Programms und kann - muss aber nicht - aufgerufen werden, um den
aktuellen Kontext durch obige eingefrorene Zukunft ersetzt werden - wenn
ich das mal so informell ausdrücken darf.

> Ich brauchte einen Moment, bis ich die letzte
> Zeile im folgenden Aktor zur Berechnung der Fakultät in einer
> an Scheme angelehnten Notation verstand:
>
> ( define factorial
> ( lambda( n c )
> ( if( = n 0 )
> ( c 1 )
> ( factorial( - n 1 )( lambda( f )( c( * f n )))))))

Vielleicht wird's einfacher, wenn du die Leerzeichen so setzen würdest,
wie es bei Scheme üblich ist - aber was rede ich, das machst du bei Java
ja auch nicht... :)

Zu obigem Beispiel zu bemerken ist übrigens noch, dass die Funktion
endrekursiv ist, was die "normale" Fakultätsfunktion nicht ist. Scheme -
das Endrekursionen erkennen und optimieren muss - würde obigen Code mit
konstantem Speicherbedarf auswerten.

Eine call/cc-Variante der Fakultätsfunktion wäre:

(define (fac/cc n)
(let* ((r 1) (k (call/cc (lambda (k) k))))
(set! r (* r n))
(set! n (- n 1))
(if (= n 0) r (k k))))

> In Java hätten wir nun ja fast Fortsetzungen, wenn Java eine
> spezielle Endrekursionsimplementation böte.

Man hat sie sogar auch ohne, aber es ist sehr ineffizient, weil sich ein
Callstack aufbaut, der niemals wieder abgebaut wird.

Übrigens, in diesem Zusammenhang: Jemand hat gerade continuations in die
Mono VM eingebaut: http://bat.org/~tomba/monoco.html

Message has been deleted

Stefan Matthias Aust

unread,
Apr 22, 2006, 11:45:47 AM4/22/06
to
Stefan Ram schrieb:

> Allerdings könnte man vielleicht etwas tricksen, indem man im
> tiefsten Keller, wenn alle Ziele, die mit einem Pfad von
> Fortsetzungen erreicht werden sollten, auch erreicht wurden,
> wirft, um den Keller auf einen Schlag leerzuräumen.
>
> Die Hauptschleife des Dienstes wäre dann:
>
> while( true ){ try{ /* ... */ } catch
> ( final ExecutionPathExhaustedThrowable
> executionPathExhaustedThrowable ){}}

Ich glaube - ohne es wirklich durchdacht zu haben - das man sich dadurch
die IMHO wichtige Eigenschaft, eine continuations mehrfach zu
durchlaufen verbaut. Exceptions sind ja auch nur eine Spezialform von
continuations, aber eben welche, die nur einmal funktionieren.

Message has been deleted

Stefan Matthias Aust

unread,
Apr 22, 2006, 12:16:11 PM4/22/06
to
Stefan Ram schrieb:

> Das wird aber doch nicht möglich sein, denn zu einer
> Fortsetzung gehören doch noch mehr Informationen als sie
> in einem Throwable aufbewahrt werden.

Nein, im Gegensatz zu Smalltalk, wo diese Kontextinformationen wirklich
als Objekte zur Verfügung stehen und auch meist manipuliert werden
können (was Seaside überhaupt ermöglicht hat, continuations zu
implementieren) ist es in Java nur ein informativ und nicht mehr an die
VM gebunden.

Das hat aber auch gute Gründe, denn man verbaut sich ansonsten einiges
an Optimierungen. Da es in Smalltalk sehr selten ist, dass man wirklich
explizit auf den Context zugreift, so erzählte mir der Autor der
VisualWorks-VM mal, haben die dort quasi zwei Betriebsmodi. Den
normalen, wo optimiert wird und die Context-Objekte eigentlich gar nicht
existieren und den, der es so macht, wie Smalltalk-80 spezifiziert ist
und Änderungen am Kontext erlaubt.

Frank Buss

unread,
Apr 22, 2006, 1:14:07 PM4/22/06
to
Stefan Matthias Aust wrote:

> Verstehe. Aber läuft das nicht entweder auf einen eingebetteten IE (mit
> dem Nachteil, das man nicht auf einem richtigen Browser wie Firefox oder
> Safari entwickeln kann) oder gar den Nachbau eines Webbrowsers hinaus?

Der Webbrowser könnte als ActiveX Komponente angezeigt und die Links von
der Entwicklungsumgebung abgefangen und ggf. direkt zur Anzeige von
Quelltext im Quelltexteditor umgeletiet werden. Das könnte ein schönes
integriertes System werden.

Unter Mac und Linux könnte man den Java-HTML-Renderer verwenden (gab's doch
irgendein Swing-Control für?). Bis das Projekt fertig ist, hat Sun das
vielleicht soweit hinbekommen, daß aktuelle Webseiten vernünftig
dargestellt werden :-)

Message has been deleted

Stefan Matthias Aust

unread,
Jun 4, 2006, 5:41:46 PM6/4/06
to
Stefan Ram schrieb:

> So etwas (auf dem Klienten) ist beispielsweise mit »narrative
> JavaScript« möglich.

Warum gräbst du alte Threads aus, um denen durchaus interessante Links
hinzuzufügen, wenn du doch gleichzeitigt alle deine Postings nicht
archivieren lässt sodass niemand wirklich davon etwas hat?

Stefan

0 new messages