[Pharo-project] little challenge for sven and us
Hi guys apparently people get excited by nodeJS and I would like to know the equivalence of var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res .end('Hello World\n'); }).listen(1337, "127.0.0.1"); console.log('Server running at http://127.0.0.1:1337/'); To run the server, put the code into a file example.js and execute it with the node program: % node example.js Server running at http://127.0.0.1:1337/ Here is an example of a simple TCP server which listens on port 1337 and echoes whatever you send it: var net = require('net'); var server = net.createServer(function (socket) { socket.write("Echo server\r\n"); socket.pipe(socket); }); server.listen(1337, "127.0.0.1"); we should communicate better :) Stef
Am 30.06.2011 um 17:07 schrieb Stéphane Ducasse:
Hi guys
apparently people get excited by nodeJS and I would like to know the equivalence of
What does it mean? Norbert
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res .end('Hello World\n'); }).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/'); To run the server, put the code into a file example.js and execute it with the node program:
% node example.js Server running at http://127.0.0.1:1337/
Here is an example of a simple TCP server which listens on port 1337 and echoes whatever you send it:
var net = require('net'); var server = net.createServer(function (socket) { socket.write("Echo server\r\n"); socket.pipe(socket); });
server.listen(1337, "127.0.0.1");
we should communicate better :)
Stef
Hi guys
apparently people get excited by nodeJS and I would like to know the equivalence of
What does it mean?
in Pharo.. how do you have the same:
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res .end('Hello World\n'); }).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/'); To run the server, put the code into a file example.js and execute it with the node program:
% node example.js Server running at http://127.0.0.1:1337/
Here is an example of a simple TCP server which listens on port 1337 and echoes whatever you send it:
var net = require('net'); var server = net.createServer(function (socket) { socket.write("Echo server\r\n"); socket.pipe(socket); });
server.listen(1337, "127.0.0.1");
we should communicate better :)
Stef
Am 30.06.2011 um 17:23 schrieb Stéphane Ducasse:
Hi guys
apparently people get excited by nodeJS and I would like to know the equivalence of
What does it mean?
in Pharo.. how do you have the same:
It depends what is in your head when you wrote this. The code snippet doesn't tell that much. Registering a Block for execution on request is probably not what makes you excited about. What is exciting about it is that javascript is written in a strictly asynchronous manner (event driven) and that matches perfectly the implementation with asynchronous I/O. Suddenly you can write programs they way you ever wanted it. And lucky for us smalltalk itself is event driven so it can go there easily, too. Well, easily would mean to have support for asynchronous I/O in the vm (file operations) and in the socket plugin at least. Is that what you asked? Norbert
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res .end('Hello World\n'); }).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/'); To run the server, put the code into a file example.js and execute it with the node program:
% node example.js Server running at http://127.0.0.1:1337/
Here is an example of a simple TCP server which listens on port 1337 and echoes whatever you send it:
var net = require('net'); var server = net.createServer(function (socket) { socket.write("Echo server\r\n"); socket.pipe(socket); });
server.listen(1337, "127.0.0.1");
we should communicate better :)
Stef
S, Norbert Hartl piše:
Am 30.06.2011 um 17:23 schrieb Stéphane Ducasse:
apparently people get excited by nodeJS and I would like to know the equivalence of
What does it mean?
in Pharo.. how do you have the same:
It depends what is in your head when you wrote this. The code snippet doesn't tell that much. Registering a Block for execution on request is probably not what makes you excited about. What is exciting about it is that javascript is written in a strictly asynchronous manner (event driven) and that matches perfectly the implementation with asynchronous I/O. Suddenly you can write programs they way you ever wanted it. And lucky for us smalltalk itself is event driven so it can go there easily, too. Well, easily would mean to have support for asynchronous I/O in the vm (file operations) and in the socket plugin at least.
Because I'm just working on asynchronous no-blocking node.js like control flow in Aida, I can say that this is really natural to Smalltalk with its closures, much more than so called callbacks in JavaScript. In Smalltalk it is more readable and you hardly notice the difference to the normal Smalltalk code, while in JavaScript those callbacks are a bit hard to grasp and understand. From non seasoned programmer perspective, that is. Best regards Janko -- Janko Mivšek Aida/Web Smalltalk Web Application Server http://www.aidaweb.si
Am 30.06.2011 um 17:53 schrieb Janko Mivšek:
S, Norbert Hartl piše:
Am 30.06.2011 um 17:23 schrieb Stéphane Ducasse:
apparently people get excited by nodeJS and I would like to know the equivalence of
What does it mean?
in Pharo.. how do you have the same:
It depends what is in your head when you wrote this. The code snippet doesn't tell that much. Registering a Block for execution on request is probably not what makes you excited about. What is exciting about it is that javascript is written in a strictly asynchronous manner (event driven) and that matches perfectly the implementation with asynchronous I/O. Suddenly you can write programs they way you ever wanted it. And lucky for us smalltalk itself is event driven so it can go there easily, too. Well, easily would mean to have support for asynchronous I/O in the vm (file operations) and in the socket plugin at least.
Because I'm just working on asynchronous no-blocking node.js like control flow in Aida, I can say that this is really natural to Smalltalk with its closures, much more than so called callbacks in JavaScript. In Smalltalk it is more readable and you hardly notice the difference to the normal Smalltalk code, while in JavaScript those callbacks are a bit hard to grasp and understand. From non seasoned programmer perspective, that is.
Can you elaborate on this? I agree that one of the biggest flaws in javascript is that you have to write function() {} to use a closure which prevents its usage in a lot of cases, e.g. in filter functions etc. It is just ugly and nobody likes it. The second point is that you need to preserve this in javascript manually if you wish to use it in closures. Apart from that I can see a single difference between the two. Callbacks are natural to javascript because most usage pattern use it. Closures are natural to smalltalk because it just needs [ ] and it is well used throughout the class library. Norbert
S, Norbert Hartl piše:
Am 30.06.2011 um 17:53 schrieb Janko Mivšek:
S, Norbert Hartl piše:
Am 30.06.2011 um 17:23 schrieb Stéphane Ducasse:
apparently people get excited by nodeJS and I would like to know the equivalence of
What does it mean?
in Pharo.. how do you have the same:
It depends what is in your head when you wrote this. The code snippet doesn't tell that much. Registering a Block for execution on request is probably not what makes you excited about. What is exciting about it is that javascript is written in a strictly asynchronous manner (event driven) and that matches perfectly the implementation with asynchronous I/O. Suddenly you can write programs they way you ever wanted it. And lucky for us smalltalk itself is event driven so it can go there easily, too. Well, easily would mean to have support for asynchronous I/O in the vm (file operations) and in the socket plugin at least.
Because I'm just working on asynchronous no-blocking node.js like control flow in Aida, I can say that this is really natural to Smalltalk with its closures, much more than so called callbacks in JavaScript. In Smalltalk it is more readable and you hardly notice the difference to the normal Smalltalk code, while in JavaScript those callbacks are a bit hard to grasp and understand. From non seasoned programmer perspective, that is.
Can you elaborate on this? I agree that one of the biggest flaws in javascript is that you have to write function() {} to use a closure which prevents its usage in a lot of cases, e.g. in filter functions etc. It is just ugly and nobody likes it. The second point is that you need to preserve this in javascript manually if you wish to use it in closures. Apart from that I can see a single difference between the two. Callbacks are natural to javascript because most usage pattern use it. Closures are natural to smalltalk because it just needs [ ] and it is well used throughout the class library.
Let me show an example by Ryan Dahl, author of node.js. First in JavaScript then how it will look in Smalltalk. Synchronous blocking database call: var result = db.query("select.."); // wait // use result Asynchronous non-blocking database call: db.query("select..", function (result) {// use result }); // continue In first case program execution is blocked until database returns result. In second case we register a callback function to deal with the result. This function will be called later when result arrives, while we don't wait but continue with execution. If you'll do in Smalltalk a blocking call: result := db query: 'select..'. result useIt A non-blocking call can look something like: db query: 'select..' thenDo: [:result | result useIt ] As you see with our closures we can much more naturally and understandably write such calls. Best regards Janko -- Janko Mivšek Svetovalec za informatiko Eranova d.o.o. Ljubljana, Slovenija www.eranova.si tel: 01 514 22 55 faks: 01 514 22 56 gsm: 031 674 565
2011/6/30 Janko Mivšek <janko.mivsek@eranova.si>:
S, Norbert Hartl piše:
Am 30.06.2011 um 17:53 schrieb Janko Mivšek:
S, Norbert Hartl piše:
Am 30.06.2011 um 17:23 schrieb Stéphane Ducasse:
apparently people get excited by nodeJS and I would like to know the equivalence of
What does it mean?
in Pharo.. how do you have the same:
It depends what is in your head when you wrote this. The code snippet doesn't tell that much. Registering a Block for execution on request is probably not what makes you excited about. What is exciting about it is that javascript is written in a strictly asynchronous manner (event driven) and that matches perfectly the implementation with asynchronous I/O. Suddenly you can write programs they way you ever wanted it. And lucky for us smalltalk itself is event driven so it can go there easily, too. Well, easily would mean to have support for asynchronous I/O in the vm (file operations) and in the socket plugin at least.
Because I'm just working on asynchronous no-blocking node.js like control flow in Aida, I can say that this is really natural to Smalltalk with its closures, much more than so called callbacks in JavaScript. In Smalltalk it is more readable and you hardly notice the difference to the normal Smalltalk code, while in JavaScript those callbacks are a bit hard to grasp and understand. From non seasoned programmer perspective, that is.
Can you elaborate on this? I agree that one of the biggest flaws in javascript is that you have to write function() {} to use a closure which prevents its usage in a lot of cases, e.g. in filter functions etc. It is just ugly and nobody likes it. The second point is that you need to preserve this in javascript manually if you wish to use it in closures. Apart from that I can see a single difference between the two. Callbacks are natural to javascript because most usage pattern use it. Closures are natural to smalltalk because it just needs [ ] and it is well used throughout the class library.
Let me show an example by Ryan Dahl, author of node.js. First in JavaScript then how it will look in Smalltalk.
Synchronous blocking database call:
    var result = db.query("select..");     // wait     // use result
Asynchronous non-blocking database call:
    db.query("select..", function (result) {// use result });     // continue
In first case program execution is blocked until database returns result. In second case we register a callback function to deal with the result. This function will be called later when result arrives, while we don't wait but continue with execution.
If you'll do in Smalltalk a blocking call:
    result := db query: 'select..'.     result useIt
A non-blocking call can look something like:
    db query: 'select..' thenDo: [:result | result useIt ]
As you see with our closures we can much more naturally and understandably write such calls.
Indeed. Actually the recent JS popular libraries coding style reminds me more and more smalltalk. Looks like they are inventing new wheel, going long road from creepy C syntax and C programming style to smalltalk.
Best regards Janko
-- Best regards, Igor Stasenko AKA sig.
Indeed. Actually the recent JS popular libraries coding style reminds me more and more smalltalk. Looks like they are inventing new wheel, going long road from creepy C syntax and C programming style to smalltalk.
The problem igor is that they will get there and fast because the world is faster. Microsoft is creating a new lab at Zurich for example. And our nice little community did not move since at least one decade. Sometimes I'm immensely sad to see for example that while julian is working for cincom he does not lead an effort to bring Seaside to the next level. Company vision are puzzling me. Stef
On 1 July 2011 07:32, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Indeed. Actually the recent JS popular libraries coding style reminds me more and more smalltalk. Looks like they are inventing new wheel, going long road from creepy C syntax and C programming style to smalltalk.
The problem igor is that they will get there and fast because the world is faster. Microsoft is creating a new lab at Zurich for example. And our nice little community did not move since at least one decade. Sometimes I'm immensely sad to see for example that while julian is working for cincom he does not lead an effort to bring Seaside to the next level. Company vision are puzzling me.
To get to the next level, first you have to define what is next level. For me , i don't see what is the next level for web application framework like seaside. Do you?
Stef
-- Best regards, Igor Stasenko AKA sig.
On Jul 1, 2011, at 10:56 AM, Igor Stasenko wrote:
On 1 July 2011 07:32, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Indeed. Actually the recent JS popular libraries coding style reminds me more and more smalltalk. Looks like they are inventing new wheel, going long road from creepy C syntax and C programming style to smalltalk.
The problem igor is that they will get there and fast because the world is faster. Microsoft is creating a new lab at Zurich for example. And our nice little community did not move since at least one decade. Sometimes I'm immensely sad to see for example that while julian is working for cincom he does not lead an effort to bring Seaside to the next level. Company vision are puzzling me.
To get to the next level, first you have to define what is next level. For me , i don't see what is the next level for web application framework like seaside. Do you?
No but I'm not in the field. Stef
On 1 July 2011 12:00, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
On Jul 1, 2011, at 10:56 AM, Igor Stasenko wrote:
On 1 July 2011 07:32, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Indeed. Actually the recent JS popular libraries coding style reminds me more and more smalltalk. Looks like they are inventing new wheel, going long road from creepy C syntax and C programming style to smalltalk.
The problem igor is that they will get there and fast because the world is faster. Microsoft is creating a new lab at Zurich for example. And our nice little community did not move since at least one decade. Sometimes I'm immensely sad to see for example that while julian is working for cincom he does not lead an effort to bring Seaside to the next level. Company vision are puzzling me.
To get to the next level, first you have to define what is next level. For me , i don't see what is the next level for web application framework like seaside. Do you?
No but I'm not in the field.
Well, to my observations, web slowly but steady closing the gap between desktop based application and remote ones. HTML5 enabling a rich graphics to be delivered to user, Web 2.0 about better interaction & dynamism of web content and so on. So, doing something in this regard could bring us to this level.
Stef
-- Best regards, Igor Stasenko AKA sig.
Am 30.06.2011 um 21:03 schrieb Janko Mivšek:
S, Norbert Hartl piše:
Am 30.06.2011 um 17:53 schrieb Janko Mivšek:
S, Norbert Hartl piše:
Am 30.06.2011 um 17:23 schrieb Stéphane Ducasse:
apparently people get excited by nodeJS and I would like to know the equivalence of
What does it mean?
in Pharo.. how do you have the same:
It depends what is in your head when you wrote this. The code snippet doesn't tell that much. Registering a Block for execution on request is probably not what makes you excited about. What is exciting about it is that javascript is written in a strictly asynchronous manner (event driven) and that matches perfectly the implementation with asynchronous I/O. Suddenly you can write programs they way you ever wanted it. And lucky for us smalltalk itself is event driven so it can go there easily, too. Well, easily would mean to have support for asynchronous I/O in the vm (file operations) and in the socket plugin at least.
Because I'm just working on asynchronous no-blocking node.js like control flow in Aida, I can say that this is really natural to Smalltalk with its closures, much more than so called callbacks in JavaScript. In Smalltalk it is more readable and you hardly notice the difference to the normal Smalltalk code, while in JavaScript those callbacks are a bit hard to grasp and understand. From non seasoned programmer perspective, that is.
Can you elaborate on this? I agree that one of the biggest flaws in javascript is that you have to write function() {} to use a closure which prevents its usage in a lot of cases, e.g. in filter functions etc. It is just ugly and nobody likes it. The second point is that you need to preserve this in javascript manually if you wish to use it in closures. Apart from that I can see a single difference between the two. Callbacks are natural to javascript because most usage pattern use it. Closures are natural to smalltalk because it just needs [ ] and it is well used throughout the class library.
Let me show an example by Ryan Dahl, author of node.js. First in JavaScript then how it will look in Smalltalk.
Synchronous blocking database call:
var result = db.query("select.."); // wait // use result
Asynchronous non-blocking database call:
db.query("select..", function (result) {// use result }); // continue
In first case program execution is blocked until database returns result. In second case we register a callback function to deal with the result. This function will be called later when result arrives, while we don't wait but continue with execution.
If you'll do in Smalltalk a blocking call:
result := db query: 'select..'. result useIt
A non-blocking call can look something like:
db query: 'select..' thenDo: [:result | result useIt ]
As you see with our closures we can much more naturally and understandably write such calls.
Ok, I don't think we need to argue that smalltalks syntax has great potential. But to be honest
db query: 'select..' thenDo: [:result | result useIt ]
doesn't feel natural to me from a smalltalk point of view. More natural appears database select: [:each| each....] So not having to use javascript syntax might be an advantage. It would be great if you would omit the SQL as well ;) If we talk about asynchronous programming I'm more concerned about composability and control of asynchronous operations then to have a nice syntax for a really simple case. Norbert
On 30 Jun 2011, at 17:53, Janko Mivšek wrote:
Because I'm just working on asynchronous no-blocking node.js like control flow in Aida, I can say that this is really natural to Smalltalk with its closures, much more than so called callbacks in JavaScript. In Smalltalk it is more readable and you hardly notice the difference to the normal Smalltalk code, while in JavaScript those callbacks are a bit hard to grasp and understand. From non seasoned programmer perspective, that is.
Janko, that sounds promising, I would really love to learn more about your efforts. How do you do async IO without the select() system call ? As far as I know, that is not available as a VM primitive. Sven
S, Sven Van Caekenberghe piše:
On 30 Jun 2011, at 17:53, Janko Mivšek wrote:
Because I'm just working on asynchronous no-blocking node.js like control flow in Aida, I can say that this is really natural to Smalltalk with its closures, much more than so called callbacks in JavaScript. In Smalltalk it is more readable and you hardly notice the difference to the normal Smalltalk code, while in JavaScript those callbacks are a bit hard to grasp and understand. From non seasoned programmer perspective, that is.
Janko, that sounds promising, I would really love to learn more about your efforts.
How do you do async IO without the select() system call ? As far as I know, that is not available as a VM primitive.
Currently I'm introducing those techniques in Aida not for I/O but for tree-like control flow. One snippet from the forthcoming ToDo list example to confirm the delete of ToDo task (see attached screenshot): link := e addNilLinkText: 'Delete this task'. link onClickPopup: (WebDialog newConfirm text: 'Do you really want to delete that task?'; ifTrue: [self observee deleteTask: aToDoTask. aListElement update]). This is typical tree-like control flow scenario. When clicking on the link, a popup with Yes/No confirmation appear. If Yes is clicked, true is returned and ifTrue: block executed. Whole point is that this is a non-blocking code, in contrast to continuation based approach like in Seaside, where similar code would block and wait until dialog component returns answer. Here need to be mentioned that Iliad also use non-blocking tree-like control flow. Best regards Janko -- Janko Mivšek Aida/Web Smalltalk Web Application Server http://www.aidaweb.si
2011/6/30 Janko Mivšek <janko.mivsek@eranova.si>
Whole point is that this is a non-blocking code, in contrast to continuation based approach like in Seaside, where similar code would block and wait until dialog component returns answer.
Janko, what are you talking about? If it's not blocking, it's just a callback. Of course Seaside can do the same thing: you just use #show:onAnswer:. Julian
S, Julian Fitzell piše:
2011/6/30 Janko Mivšek <janko.mivsek@eranova.si
Whole point is that this is a non-blocking code, in contrast to continuation based approach like in Seaside, where similar code would block and wait until dialog component returns answer.
Janko, what are you talking about? If it's not blocking, it's just a callback. Of course Seaside can do the same thing: you just use #show:onAnswer:.
Isn't the whole point of Seaside and continuations to enable worklow like in below example from the HPI Seaside tutorial? This code is blocking until the call: returns, isn't that so?
From HPI tutorial [1], chapter 5-Forms, figure 5-2 :
(self call: self taskEditor) ifTrue: [aTask copyFrom: self taskEditor task] Text bellow: "Even better, Seaside remembers the position in your code and runs it from there again, after the called component finished. This means, #call: blocks your current component, that is your callback evaluation, waits for the called component to be finished, and afterwards goes on with your callback. " [1] http://www.hpi.uni-potsdam.de/hirschfeld/seaside/tutorial Janko -- Janko Mivšek Aida/Web Smalltalk Web Application Server http://www.aidaweb.si
On 07/01/2011 12:47 PM, Janko Mivšek wrote:
S, Julian Fitzell piše:
2011/6/30 Janko Mivšek <janko.mivsek@eranova.si
Whole point is that this is a non-blocking code, in contrast to continuation based approach like in Seaside, where similar code would block and wait until dialog component returns answer.
Janko, what are you talking about? If it's not blocking, it's just a callback. Of course Seaside can do the same thing: you just use #show:onAnswer:.
Isn't the whole point of Seaside and continuations to enable worklow like in below example from the HPI Seaside tutorial? This code is blocking until the call: returns, isn't that so?
From HPI tutorial [1], chapter 5-Forms, figure 5-2 :
(self call: self taskEditor) ifTrue: [aTask copyFrom: self taskEditor task]
Text bellow: "Even better, Seaside remembers the position in your code and runs it from there again, after the called component finished. This means, #call: blocks your current component, that is your callback evaluation, waits for the called component to be finished, and afterwards goes on with your callback. "
Yes, but continuations don't block a Process. All they do is allow you to write code that is more readable. Instead of self call: self taskEditor [ :value | value ifTrue: [ aTask copyFrom: self taskEditor task ] ] you can write (self call: self taskEditor) ifTrue: [aTask copyFrom: self taskEditor task] There is no Process in the background waiting or anything. In this simple case the benefit may not be that obvious but look at the case with only two steps. first := self askForFirstObject. second := self askForSecondObject. (first aSelector: second) ifTrue: [ self something ] ifFalse: [ self somethingElse ] Sure you could write that in CSP but would you really want to? Cheers Philippe
S, Philippe Marschall piše:
On 07/01/2011 12:47 PM, Janko Mivšek wrote:
S, Julian Fitzell piše:
2011/6/30 Janko Mivšek <janko.mivsek@eranova.si
Whole point is that this is a non-blocking code, in contrast to continuation based approach like in Seaside, where similar code would block and wait until dialog component returns answer.
Janko, what are you talking about? If it's not blocking, it's just a callback. Of course Seaside can do the same thing: you just use #show:onAnswer:.
Isn't the whole point of Seaside and continuations to enable worklow like in below example from the HPI Seaside tutorial? This code is blocking until the call: returns, isn't that so?
From HPI tutorial [1], chapter 5-Forms, figure 5-2 :
(self call: self taskEditor) ifTrue: [aTask copyFrom: self taskEditor task]
Text bellow: "Even better, Seaside remembers the position in your code and runs it from there again, after the called component finished. This means, #call: blocks your current component, that is your callback evaluation, waits for the called component to be finished, and afterwards goes on with your callback. "
Yes, but continuations don't block a Process. All they do is allow you to write code that is more readable.
Yes, technically it doesn't block that process because it must return something to the browser, but method execution actually blocks on that point. This blocking is not as hard as blocking like on long I/O, but it is still. While on the other side a non-blocking style continues execution of that method instead. Here is the point, and main diffenrec of blocking vs. non-blocking styles.
Instead of
self call: self taskEditor [ :value | value ifTrue: [ aTask copyFrom: self taskEditor task ] ]
you can write
(self call: self taskEditor) ifTrue: [aTask copyFrom: self taskEditor task]
There is no Process in the background waiting or anything.
In this simple case the benefit may not be that obvious but look at the case with only two steps.
first := self askForFirstObject. second := self askForSecondObject. (first aSelector: second) ifTrue: [ self something ] ifFalse: [ self somethingElse ]
Asynchronous way would be something like: self askForFirstObject onAnswerDo: [:first | self askForSecondObject onAnswerDo: [:second | (first aSelector: second) ifTrue: [self something] ifFalse: [self somethingElse] ] ] This surely looks less nice than your example but it is closer to event driven nature of browser and web apps. And because such workflow is actually rare, it is IMHO not worth such a big expense in framework complexity. Best regards Janko -- Janko Mivšek Aida/Web Smalltalk Web Application Server http://www.aidaweb.si
On 07/01/2011 01:38 PM, Janko Mivšek wrote:
S, Philippe Marschall piše:
On 07/01/2011 12:47 PM, Janko Mivšek wrote:
S, Julian Fitzell piše:
2011/6/30 Janko Mivšek <janko.mivsek@eranova.si
Whole point is that this is a non-blocking code, in contrast to continuation based approach like in Seaside, where similar code would block and wait until dialog component returns answer.
Janko, what are you talking about? If it's not blocking, it's just a callback. Of course Seaside can do the same thing: you just use #show:onAnswer:.
Isn't the whole point of Seaside and continuations to enable worklow like in below example from the HPI Seaside tutorial? This code is blocking until the call: returns, isn't that so?
From HPI tutorial [1], chapter 5-Forms, figure 5-2 :
(self call: self taskEditor) ifTrue: [aTask copyFrom: self taskEditor task]
Text bellow: "Even better, Seaside remembers the position in your code and runs it from there again, after the called component finished. This means, #call: blocks your current component, that is your callback evaluation, waits for the called component to be finished, and afterwards goes on with your callback. "
Yes, but continuations don't block a Process. All they do is allow you to write code that is more readable.
Yes, technically it doesn't block that process because it must return something to the browser, but method execution actually blocks on that point.
No. The method terminates. Cheers Philippe
S, Philippe Marschall piše:
On 07/01/2011 01:38 PM, Janko Mivšek wrote:
Isn't the whole point of Seaside and continuations to enable worklow like in below example from the HPI Seaside tutorial? This code is blocking until the call: returns, isn't that so?
From HPI tutorial [1], chapter 5-Forms, figure 5-2 :
(self call: self taskEditor) ifTrue: [aTask copyFrom: self taskEditor task]
Text bellow: "Even better, Seaside remembers the position in your code and runs it from there again, after the called component finished. This means, #call: blocks your current component, that is your callback evaluation, waits for the called component to be finished, and afterwards goes on with your callback. "
Yes, but continuations don't block a Process. All they do is allow you to write code that is more readable.
Yes, technically it doesn't block that process because it must return something to the browser, but method execution actually blocks on that point.
No. The method terminates.
It terminates from internal framework point of view. But from application programmer point of view it blocks. If I put Transcript messages in your example: first := self askForFirstObject. Transcript show: 'first answered' second := self askForSecondObject. Transcript show: 'second answered' How will messages show up, immediately or waiting for answers first? Best regards Janko -- Janko Mivšek Aida/Web Smalltalk Web Application Server http://www.aidaweb.si
Hello 2011/7/1 Janko Mivšek <janko.mivsek@eranova.si>
S, Philippe Marschall piše:
first := self askForFirstObject. second := self askForSecondObject. (first aSelector: second) ifTrue: [ self something ] ifFalse: [ self somethingElse ]
Asynchronous way would be something like:
self askForFirstObject onAnswerDo: [:first | self askForSecondObject onAnswerDo: [:second | (first aSelector: second) ifTrue: [self something] ifFalse: [self somethingElse] ] ]
Ok. But how you rewrite more complex control flow example: first := self askForFirstObject. second := self askForSecondObject. (first aSelector: second) ifTrue: [ target := self askForThirdObject] ifFalse: [ target := self askForLastObject ]. self saveToDB: target. self show: target. self show: first. self show: second. Maybe like this: self askForFirstObject onAnswerDo: [:first | self askForSecondObject onAnswerDo: [:second | (first aSelector: second) ifTrue: [self askForThirdObject onAnswerDo: [:target | self saveToDB: target. self show: target. self show: first. self show: second. ] ifFalse: [self askForLastObject onAnswerDo: [:target | self saveToDB: target. self show: target. self show: first. self show: second] ] ]. Are you really like this code? I think no. And when interraction logic become more difficult you will get more and more complex fragile code. I think continuations based synch approach should be core of any UI framework (not just web). But web browsers can't do this :( This surely looks less nice than your example but it is closer to event
driven nature of browser and web apps. And because such workflow is
actually rare, it is IMHO not worth such a big expense in framework complexity.
Best regards
Janko
-- Janko Mivšek Aida/Web Smalltalk Web Application Server http://www.aidaweb.si
Am 01.07.2011 um 12:47 schrieb Janko Mivšek:
S, Julian Fitzell piše:
2011/6/30 Janko Mivšek <janko.mivsek@eranova.si
Whole point is that this is a non-blocking code, in contrast to continuation based approach like in Seaside, where similar code would block and wait until dialog component returns answer.
Janko, what are you talking about? If it's not blocking, it's just a callback. Of course Seaside can do the same thing: you just use #show:onAnswer:.
Isn't the whole point of Seaside and continuations to enable worklow like in below example from the HPI Seaside tutorial? This code is blocking until the call: returns, isn't that so?
From HPI tutorial [1], chapter 5-Forms, figure 5-2 :
(self call: self taskEditor) ifTrue: [aTask copyFrom: self taskEditor task]
Text bellow: "Even better, Seaside remembers the position in your code and runs it from there again, after the called component finished. This means, #call: blocks your current component, that is your callback evaluation, waits for the called component to be finished, and afterwards goes on with your callback. "
Janko, it is just the style of continuity you choose. If you want to do an asynchronous thing than you split your method into two parts. The first registers the second part as callback anywhere and if the callback is activated the second part of your method is executed. That can be very cumbersome if you have to split it all up. With continuations you split the code at the point the continuation is created. You return from that method and if the callback (the continuation) is invoked you just step into the old method and proceed from there. The only difference I can see is that the latter is far more elegant and powerful. Norbert
2011/7/1 Janko Mivšek <janko.mivsek@eranova.si>
S, Julian Fitzell piše:
2011/6/30 Janko Mivšek <janko.mivsek@eranova.si
Whole point is that this is a non-blocking code, in contrast to continuation based approach like in Seaside, where similar code would block and wait until dialog component returns answer.
Janko, what are you talking about? If it's not blocking, it's just a callback. Of course Seaside can do the same thing: you just use #show:onAnswer:.
Isn't the whole point of Seaside and continuations to enable worklow like in below example from the HPI Seaside tutorial?
No. That's the point of one particular feature of Seaside.
This code is blocking until the call: returns, isn't that so?
Yes, you are correct.
From HPI tutorial [1], chapter 5-Forms, figure 5-2 :
(self call: self taskEditor) ifTrue: [aTask copyFrom: self taskEditor task]
Text bellow: "Even better, Seaside remembers the position in your code and runs it from there again, after the called component finished. This means, #call: blocks your current component, that is your callback evaluation, waits for the called component to be finished, and afterwards goes on with your callback. "
Of course. #call: both creates a continuation and interrupts the action phase of request handling (beginning response generation immediately). What I said was if you don't want to "block", you can use #show:onAnswer: instead. That method will delegate to the desired component and specify a block of code to call whenever that component answers. Then it will return and your code will keep running. Julian
In Smalltalk it is more readable and you hardly notice the difference to the normal Smalltalk code, while in JavaScript those callbacks are a bit hard to grasp and understand.
+1 2011/6/30 Janko Mivšek <janko.mivsek@eranova.si>
S, Norbert Hartl piše:
Am 30.06.2011 um 17:23 schrieb Stéphane Ducasse:
apparently people get excited by nodeJS and I would like to know the equivalence of
What does it mean?
in Pharo.. how do you have the same:
It depends what is in your head when you wrote this. The code snippet doesn't tell that much. Registering a Block for execution on request is probably not what makes you excited about. What is exciting about it is that javascript is written in a strictly asynchronous manner (event driven) and that matches perfectly the implementation with asynchronous I/O. Suddenly you can write programs they way you ever wanted it. And lucky for us smalltalk itself is event driven so it can go there easily, too. Well, easily would mean to have support for asynchronous I/O in the vm (file operations) and in the socket plugin at least.
Because I'm just working on asynchronous no-blocking node.js like control flow in Aida, I can say that this is really natural to Smalltalk with its closures, much more than so called callbacks in JavaScript. In Smalltalk it is more readable and you hardly notice the difference to the normal Smalltalk code, while in JavaScript those callbacks are a bit hard to grasp and understand. From non seasoned programmer perspective, that is.
Best regards Janko
-- Janko Mivšek Aida/Web Smalltalk Web Application Server http://www.aidaweb.si
On 06/30/2011 05:37 PM, Norbert Hartl wrote:
Am 30.06.2011 um 17:23 schrieb Stéphane Ducasse:
Hi guys
apparently people get excited by nodeJS and I would like to know the equivalence of
What does it mean?
in Pharo.. how do you have the same:
It depends what is in your head when you wrote this. The code snippet doesn't tell that much. Registering a Block for execution on request is probably not what makes you excited about. What is exciting about it is that javascript is written in a strictly asynchronous manner (event driven) and that matches perfectly the implementation with asynchronous I/O. Suddenly you can write programs they way you ever wanted it. And lucky for us smalltalk itself is event driven so it can go there easily, too. ...
In theory yes, in pratice no. You need to to async all the way down and then all the libraries (DNS, SQL, HTTP, â¦) need to be rewritten to be async. then your code will read like this and exception handling is impossible. You can make it read like sync code again with continuations but you still have to solve the exception problem. At that point you have gained what exactly besides being trendy? Don't get me wrong, async has it's place but not in user code. Node has to be async because it has only a single process and a single green thread but we don't. Cheers Philippe
Hi Philippe, In theory yes, in pratice no. You need to to async all the way down and
then all the libraries (DNS, SQL, HTTP, â¦) need to be rewritten to be async.
then your code will read like this
and exception handling is impossible. You can make it read like sync code again with continuations but you still have to solve the exception problem. At that point you have gained what exactly besides being trendy? Don't get me wrong, async has it's place but not in user code. Node has to be async because it has only a single process and a single green thread but we don't.
Thanks for the hype busting and for clearest explanation I've yet seen on Internet as to why Node.js is designed the way it as. The CSP analogy is interesting - I hadn't thought of it that way. Nick
Am 01.07.2011 um 13:10 schrieb Philippe Marschall:
On 06/30/2011 05:37 PM, Norbert Hartl wrote:
Am 30.06.2011 um 17:23 schrieb Stéphane Ducasse:
Hi guys
apparently people get excited by nodeJS and I would like to know the equivalence of
What does it mean?
in Pharo.. how do you have the same:
It depends what is in your head when you wrote this. The code snippet doesn't tell that much. Registering a Block for execution on request is probably not what makes you excited about. What is exciting about it is that javascript is written in a strictly asynchronous manner (event driven) and that matches perfectly the implementation with asynchronous I/O. Suddenly you can write programs they way you ever wanted it. And lucky for us smalltalk itself is event driven so it can go there easily, too. ...
In theory yes, in pratice no. You need to to async all the way down and then all the libraries (DNS, SQL, HTTP, â¦) need to be rewritten to be async.
then your code will read like this
and exception handling is impossible. You can make it read like sync code again with continuations but you still have to solve the exception problem. At that point you have gained what exactly besides being trendy? Don't get me wrong, async has it's place but not in user code. Node has to be async because it has only a single process and a single green thread but we don't.
You don't need to write everything asynchron. In javascript you would to because there is no blocking at all (only in node on system level). In Smalltalk you can just block a call while you are waiting for a callback to fire and you break the chain. So asnych stuff here is not that viral. But you don't have the opportunities like you have in javascript. In javascript you don't have most concurrency problems because it is just a single thread that can only execute one single whole function at a time. That is different in smalltalk thus making the whole async stuff less admirable. Norbert
On 07/01/2011 01:10 PM, Philippe Marschall wrote:
On 06/30/2011 05:37 PM, Norbert Hartl wrote:
Am 30.06.2011 um 17:23 schrieb Stéphane Ducasse:
Hi guys
apparently people get excited by nodeJS and I would like to know the equivalence of
What does it mean?
in Pharo.. how do you have the same:
It depends what is in your head when you wrote this. The code snippet doesn't tell that much. Registering a Block for execution on request is probably not what makes you excited about. What is exciting about it is that javascript is written in a strictly asynchronous manner (event driven) and that matches perfectly the implementation with asynchronous I/O. Suddenly you can write programs they way you ever wanted it. And lucky for us smalltalk itself is event driven so it can go there easily, too. ...
In theory yes, in pratice no. You need to to async all the way down and then all the libraries (DNS, SQL, HTTP, â¦) need to be rewritten to be async.
then your code will read like this
and exception handling is impossible. You can make it read like sync code again with continuations but you still have to solve the exception problem. At that point you have gained what exactly besides being trendy? Don't get me wrong, async has it's place but not in user code. Node has to be async because it has only a single process and a single green thread but we don't.
To illustrate that point: https://github.com/koush/node/wiki/%22async%22-support-in-node.js Cheers Philippe
Stéphane, That's not really a challenge ;-) The second example is too simple to be useful, but this would be the Zn equivalent: (ZnServer defaultOn: 1337) logToTranscript; delegate: (ZnValueDelegate with: [ :request | ZnResponse ok: (ZnEntity text: 'Hello World!') ]); start. ZnClient get: 'http://localhost:1337'. (ZnServer defaultOn: 1337) logToTranscript; delegate: (ZnValueDelegate with: [ :request | ZnResponse ok: (ZnEntity with: request contents) ]); start. ZnClient post: 'http://localhost:1337' data: (ZnEntity text: 'Echo'). ZnServer stopDefault. Smalltalk is a beautiful language, isn't it ? Sven PS: the delegate object has to respond to #handleRequest:. In earlier versions, it was a block, now ZnValueDelegate translates #handleRequest: to #value:. I thought that was clearer. For publicity reasons, maybe I could add a #delegateBlock: convencience accessor. On 30 Jun 2011, at 17:07, Stéphane Ducasse wrote:
Hi guys
apparently people get excited by nodeJS and I would like to know the equivalence of
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res .end('Hello World\n'); }).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/'); To run the server, put the code into a file example.js and execute it with the node program:
% node example.js Server running at http://127.0.0.1:1337/
Here is an example of a simple TCP server which listens on port 1337 and echoes whatever you send it:
var net = require('net'); var server = net.createServer(function (socket) { socket.write("Echo server\r\n"); socket.pipe(socket); });
server.listen(1337, "127.0.0.1");
we should communicate better :)
Stef
That's not really a challenge ;-)
Excellent I like to hear that :) Now we should add it on the web somewhere because this is the second lesson. We are not really good at communication. Stef
The second example is too simple to be useful, but this would be the Zn equivalent:
(ZnServer defaultOn: 1337) logToTranscript; delegate: (ZnValueDelegate with: [ :request | ZnResponse ok: (ZnEntity text: 'Hello World!') ]); start.
ZnClient get: 'http://localhost:1337'.
(ZnServer defaultOn: 1337) logToTranscript; delegate: (ZnValueDelegate with: [ :request | ZnResponse ok: (ZnEntity with: request contents) ]); start.
ZnClient post: 'http://localhost:1337' data: (ZnEntity text: 'Echo').
ZnServer stopDefault.
Smalltalk is a beautiful language, isn't it ?
Sven
PS: the delegate object has to respond to #handleRequest:. In earlier versions, it was a block, now ZnValueDelegate translates #handleRequest: to #value:. I thought that was clearer. For publicity reasons, maybe I could add a #delegateBlock: convencience accessor.
On 30 Jun 2011, at 17:07, Stéphane Ducasse wrote:
Hi guys
apparently people get excited by nodeJS and I would like to know the equivalence of
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res .end('Hello World\n'); }).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/'); To run the server, put the code into a file example.js and execute it with the node program:
% node example.js Server running at http://127.0.0.1:1337/
Here is an example of a simple TCP server which listens on port 1337 and echoes whatever you send it:
var net = require('net'); var server = net.createServer(function (socket) { socket.write("Echo server\r\n"); socket.pipe(socket); });
server.listen(1337, "127.0.0.1");
we should communicate better :)
Stef
(ZnServer defaultOn: 1337) logToTranscript; delegate: (ZnValueDelegate with: [ :request | ZnResponse ok: (ZnEntity text: 'Hello World!') ]); start.
ZnClient get: 'http://localhost:1337'.
(ZnServer defaultOn: 1337) logToTranscript; delegate: (ZnValueDelegate with: [ :request | ZnResponse ok: (ZnEntity with: request contents) ]); start.
ZnClient post: 'http://localhost:1337' data: (ZnEntity text: 'Echo').
ZnServer stopDefault.
Smalltalk is a beautiful language, isn't it ?
or even: hello world: ((ZnServer defaultOn: 1337) delegate: (ZnDispatcherDelegate new map: '/' to: [ :request :response | response entity: (ZnEntity text: 'Hello World!') ])) start echo: ((ZnServer defaultOn: 1337) delegate: (ZnDispatcherDelegate new map: '/' to: [ :request :response | response entity: (ZnEntity with: request contents) ])) start
On 01 Jul 2011, at 12:31, Nick Ager wrote:
or even:
hello world: ((ZnServer defaultOn: 1337) delegate: (ZnDispatcherDelegate new map: '/' to: [ :request :response | response entity: (ZnEntity text: 'Hello World!') ])) start
echo: ((ZnServer defaultOn: 1337) delegate: (ZnDispatcherDelegate new map: '/' to: [ :request :response | response entity: (ZnEntity with: request contents) ])) start
Yes, of course Nick, but then you better use the prefixes: ((ZnServer defaultOn: 1337) delegate: (ZnDispatcherDelegate new map: '/hello' to: [ :request :response | response entity: (ZnEntity text: 'Hello World!') ])) start ((ZnServer defaultOn: 1337) delegate: (ZnDispatcherDelegate new map: '/echo' to: [ :request :response | response entity: (ZnEntity with: request contents) ])) start Writing the shortest possible server code is a dubioius challenge. Although few Smalltalker would be happy to use verbose and heavy Java and XML. It is important that simple things be easy, short and elegant and complex things be possible. Sven
On 1 July 2011 12:39, Sven Van Caekenberghe <sven@beta9.be> wrote:
On 01 Jul 2011, at 12:31, Nick Ager wrote:
or even:
hello world: ((ZnServer defaultOn: 1337)    delegate: (ZnDispatcherDelegate new        map: '/' to: [ :request :response | response entity: (ZnEntity text:  'Hello World!') ])) start
echo: ((ZnServer defaultOn: 1337)    delegate: (ZnDispatcherDelegate new        map: '/' to: [ :request :response | response entity: (ZnEntity with: request contents) ])) start
Yes, of course Nick, but then you better use the prefixes:
((ZnServer defaultOn: 1337)     delegate: (ZnDispatcherDelegate new         map: '/hello' to: [ :request :response | response entity: (ZnEntity text:  'Hello World!') ])) start
((ZnServer defaultOn: 1337)    delegate: (ZnDispatcherDelegate new         map: '/echo' to: [ :request :response | response entity: (ZnEntity with: request contents) ])) start
Writing the shortest possible server code is a dubioius challenge. Although few Smalltalker would be happy to use verbose and heavy Java and XML. It is important that simple things be easy, short and elegant and complex things be possible.
The problem with such short examples is that they usually serve as a advertisement to attract new users, but has nothing to do with reality. Because once you put a real requirements before a framework which you would like to use for your needs, and measure how easy/fast you could implement it, then you realising that simple things are not so simple as shown in 'hello world' examples. So, such pieces of code could actually thwart users away: because once you hit a wall (and you will always hit it no matter what framework you using), the first reaction could be: - hey but you said it will be easy! :)
Sven
-- Best regards, Igor Stasenko AKA sig.
Am 01.07.2011 um 12:47 schrieb Igor Stasenko:
On 1 July 2011 12:39, Sven Van Caekenberghe <sven@beta9.be> wrote:
On 01 Jul 2011, at 12:31, Nick Ager wrote:
or even:
hello world: ((ZnServer defaultOn: 1337) delegate: (ZnDispatcherDelegate new map: '/' to: [ :request :response | response entity: (ZnEntity text: 'Hello World!') ])) start
echo: ((ZnServer defaultOn: 1337) delegate: (ZnDispatcherDelegate new map: '/' to: [ :request :response | response entity: (ZnEntity with: request contents) ])) start
Yes, of course Nick, but then you better use the prefixes:
((ZnServer defaultOn: 1337) delegate: (ZnDispatcherDelegate new map: '/hello' to: [ :request :response | response entity: (ZnEntity text: 'Hello World!') ])) start
((ZnServer defaultOn: 1337) delegate: (ZnDispatcherDelegate new map: '/echo' to: [ :request :response | response entity: (ZnEntity with: request contents) ])) start
Writing the shortest possible server code is a dubioius challenge. Although few Smalltalker would be happy to use verbose and heavy Java and XML. It is important that simple things be easy, short and elegant and complex things be possible.
The problem with such short examples is that they usually serve as a advertisement to attract new users, but has nothing to do with reality. Because once you put a real requirements before a framework which you would like to use for your needs, and measure how easy/fast you could implement it, then you realising that simple things are not so simple as shown in 'hello world' examples. So, such pieces of code could actually thwart users away: because once you hit a wall (and you will always hit it no matter what framework you using), the first reaction could be: - hey but you said it will be easy!
:)
And if you wouldn't say it they won't even try it at first. Norbert
On 1 July 2011 13:13, Norbert Hartl <norbert@hartl.name> wrote:
Am 01.07.2011 um 12:47 schrieb Igor Stasenko:
On 1 July 2011 12:39, Sven Van Caekenberghe <sven@beta9.be> wrote:
On 01 Jul 2011, at 12:31, Nick Ager wrote:
or even:
hello world:
((ZnServer defaultOn: 1337)
   delegate: (ZnDispatcherDelegate new
       map: '/' to: [ :request :response | response entity: (ZnEntity text:  'Hello World!') ])) start
echo:
((ZnServer defaultOn: 1337)
   delegate: (ZnDispatcherDelegate new
       map: '/' to: [ :request :response | response entity: (ZnEntity with: request contents) ])) start
Yes, of course Nick, but then you better use the prefixes:
((ZnServer defaultOn: 1337)
    delegate: (ZnDispatcherDelegate new
        map: '/hello' to: [ :request :response | response entity: (ZnEntity text:  'Hello World!') ])) start
((ZnServer defaultOn: 1337)
   delegate: (ZnDispatcherDelegate new
        map: '/echo' to: [ :request :response | response entity: (ZnEntity with: request contents) ])) start
Writing the shortest possible server code is a dubioius challenge. Although few Smalltalker would be happy to use verbose and heavy Java and XML. It is important that simple things be easy, short and elegant and complex things be possible.
The problem with such short examples is that they usually serve as a advertisement to attract new users, but has nothing to do with reality. Because once you put a real requirements before a framework which you would like to use for your needs, and measure how easy/fast you could implement it, then you realising that simple things are not so simple as shown in 'hello world' examples. So, such pieces of code could actually thwart users away: because once you hit a wall (and you will always hit it no matter what framework you using), the first reaction could be: - hey but you said it will be easy!
:)
And if you wouldn't say it they won't even try it at first.
No, i think that showing a real-world example, a nice killer app implemented on top of your framework will sell it much better than silly and useless helloworld code snippets.
Norbert
-- Best regards, Igor Stasenko AKA sig.
Hi Sven, Why not simply: (ZnServer startOn: 1337) onRequestRespond: [:request |: ZnResponse ok: 'Hello world'] This is the closest form to that node.js example and really show the power of Smalltalk and its closures. Also understandable to everyone including the (IMHO) majority, who don't understand design patterns like Delegate well. Best regards Janko S, Sven Van Caekenberghe piše:
On 01 Jul 2011, at 12:31, Nick Ager wrote:
or even:
hello world: ((ZnServer defaultOn: 1337) delegate: (ZnDispatcherDelegate new map: '/' to: [ :request :response | response entity: (ZnEntity text: 'Hello World!') ])) start
echo: ((ZnServer defaultOn: 1337) delegate: (ZnDispatcherDelegate new map: '/' to: [ :request :response | response entity: (ZnEntity with: request contents) ])) start
Yes, of course Nick, but then you better use the prefixes:
((ZnServer defaultOn: 1337) delegate: (ZnDispatcherDelegate new map: '/hello' to: [ :request :response | response entity: (ZnEntity text: 'Hello World!') ])) start
((ZnServer defaultOn: 1337) delegate: (ZnDispatcherDelegate new map: '/echo' to: [ :request :response | response entity: (ZnEntity with: request contents) ])) start
Writing the shortest possible server code is a dubioius challenge. Although few Smalltalker would be happy to use verbose and heavy Java and XML. It is important that simple things be easy, short and elegant and complex things be possible.
Sven
-- Janko Mivšek Svetovalec za informatiko Eranova d.o.o. Ljubljana, Slovenija www.eranova.si tel: 01 514 22 55 faks: 01 514 22 56 gsm: 031 674 565
On 01 Jul 2011, at 12:53, Janko Mivšek wrote:
Why not simply:
(ZnServer startOn: 1337) onRequestRespond: [:request |: ZnResponse ok: 'Hello world']
This is the closest form to that node.js example and really show the power of Smalltalk and its closures. Also understandable to everyone including the (IMHO) majority, who don't understand design patterns like Delegate well.
If you compare all the Zn delegates that are included, such as Nick's ZnDispatcherDelegate, I think it is clear that #handleRequest: is a good interface. Different use cases require delegate's with more or less features and thus complexity. But for the sake of short/elegant examples, I added the ZnSingleThreadedServer>>#onRequestRespond: convenience method, so the examples now become: (ZnServer startDefaultOn: 1337) onRequestRespond: [ :request | ZnResponse ok: (ZnEntity text: 'Hello World!') ]. and (ZnServer startDefaultOn: 1337) onRequestRespond: [ :request | ZnResponse ok: (ZnEntity with: request contents) ]. Sven
S, Sven Van Caekenberghe piše:
On 01 Jul 2011, at 12:53, Janko Mivšek wrote:
Why not simply:
(ZnServer startOn: 1337) onRequestRespond: [:request |: ZnResponse ok: 'Hello world']
This is the closest form to that node.js example and really show the power of Smalltalk and its closures. Also understandable to everyone including the (IMHO) majority, who don't understand design patterns like Delegate well.
If you compare all the Zn delegates that are included, such as Nick's ZnDispatcherDelegate, I think it is clear that #handleRequest: is a good interface. Different use cases require delegate's with more or less features and thus complexity.
But for the sake of short/elegant examples, I added the ZnSingleThreadedServer>>#onRequestRespond: convenience method, so the examples now become:
(ZnServer startDefaultOn: 1337) onRequestRespond: [ :request | ZnResponse ok: (ZnEntity text: 'Hello World!') ].
and
(ZnServer startDefaultOn: 1337) onRequestRespond: [ :request | ZnResponse ok: (ZnEntity with: request contents) ].
I'd just introduce yet that ZnResponse ok: 'Hello world'. To cover the most common response body and this will be really easy to grasp for newcomers. Nothing specially to learn upfront, just that simple two lines with seamless way to respond with some text. This complicate a bit Zinc internals, but the gain on simplicity on API level is IMHO worth that. Janko
On 01 Jul 2011, at 15:52, Janko Mivšek wrote:
I'd just introduce yet that ZnResponse ok: 'Hello world'. To cover the most common response body and this will be really easy to grasp for newcomers. Nothing specially to learn upfront, just that simple two lines with seamless way to respond with some text.
This complicate a bit Zinc internals, but the gain on simplicity on API level is IMHO worth that.
I saw your code, and I considered it, but it feels too much out of place (the implementation that is), architecturally wrong and not that usefull. Although ZnResponse ok: (ZnEntity text: 'Hello World!') is longer it is also more intention revealing, it tells you something about HTTP without being too verbose. These are opinions and aesthetics, of course. Sven
On 1 July 2011 16:55, Sven Van Caekenberghe <sven@beta9.be> wrote:
On 01 Jul 2011, at 15:52, Janko Mivšek wrote:
I'd just introduce yet that ZnResponse ok: 'Hello world'. To cover the most common response body and this will be really easy to grasp for newcomers. Nothing specially to learn upfront, just that simple two lines with seamless way to respond with some text.
This complicate a bit Zinc internals, but the gain on simplicity on API level is IMHO worth that.
I saw your code, and I considered it, but it feels too much out of place (the implementation that is), architecturally wrong and not that usefull. Although ZnResponse ok: (ZnEntity text: 'Hello World!') is longer it is also more intention revealing, it tells you something about HTTP without being too verbose.
These are opinions and aesthetics, of course.
IMO. API should be focused on most often use cases. Not on useless cases , like showing 'hello world'. Because going that road, you will just ruin the beautiful design of what you really need in favor of supporting useless things.
Sven
-- Best regards, Igor Stasenko AKA sig.
I could see some value to supporting an asZnEntity protocol. As an example, say I have an API which needs to support various output formats. I could build my classes to use the appropriate entity builder when responding to asZnEntity so that in the server code I only need to do ZnResponse ok: myresponse asZnEntity, or just ZnResponse ok: myresponse if ok: sends asZnEntity. Matt On Jul 1, 2011, at 11:12 AM, Igor Stasenko wrote:
On 1 July 2011 16:55, Sven Van Caekenberghe <sven@beta9.be> wrote:
On 01 Jul 2011, at 15:52, Janko Mivšek wrote:
I'd just introduce yet that ZnResponse ok: 'Hello world'. To cover the most common response body and this will be really easy to grasp for newcomers. Nothing specially to learn upfront, just that simple two lines with seamless way to respond with some text.
This complicate a bit Zinc internals, but the gain on simplicity on API level is IMHO worth that.
I saw your code, and I considered it, but it feels too much out of place (the implementation that is), architecturally wrong and not that usefull. Although ZnResponse ok: (ZnEntity text: 'Hello World!') is longer it is also more intention revealing, it tells you something about HTTP without being too verbose.
These are opinions and aesthetics, of course.
IMO. API should be focused on most often use cases. Not on useless cases , like showing 'hello world'. Because going that road, you will just ruin the beautiful design of what you really need in favor of supporting useless things.
Sven
-- Best regards, Igor Stasenko AKA sig.
On 01 Jul 2011, at 20:33, Matt Kennedy wrote:
I could see some value to supporting an asZnEntity protocol. As an example, say I have an API which needs to support various output formats. I could build my classes to use the appropriate entity builder when responding to asZnEntity so that in the server code I only need to do ZnResponse ok: myresponse asZnEntity, or just ZnResponse ok: myresponse if ok: sends asZnEntity.
Yes, that is indeed possible, although I am not sure if lots of asXX methods all over are a good idea. The problem is that there is no really useful one to one mapping between Smalltalk objects and Entities. An Entity has a content type (mime type) and a content length (rendered byte size) and knows how to represent itself on a binary stream or read itself from a binary stream. Now, given a String or a ByteArray, it is indeed possible to quickly convert to an Entity (ZnEntity class>>#with: does that). But that is not enough: one has to indicate a useful content type (ZnEntity class>#text: and #html: are examples of doing this automatically). In general though, there is no way to hide the need to set the actual type (ZnEntity class>>#with:type:). So you need #asZnEntityOfType: which would add parenthesis again. Sven
;D Stef On Jul 1, 2011, at 2:23 PM, Sven Van Caekenberghe wrote:
On 01 Jul 2011, at 12:53, Janko Mivšek wrote:
Why not simply:
(ZnServer startOn: 1337) onRequestRespond: [:request |: ZnResponse ok: 'Hello world']
This is the closest form to that node.js example and really show the power of Smalltalk and its closures. Also understandable to everyone including the (IMHO) majority, who don't understand design patterns like Delegate well.
If you compare all the Zn delegates that are included, such as Nick's ZnDispatcherDelegate, I think it is clear that #handleRequest: is a good interface. Different use cases require delegate's with more or less features and thus complexity.
But for the sake of short/elegant examples, I added the ZnSingleThreadedServer>>#onRequestRespond: convenience method, so the examples now become:
(ZnServer startDefaultOn: 1337) onRequestRespond: [ :request | ZnResponse ok: (ZnEntity text: 'Hello World!') ].
and
(ZnServer startDefaultOn: 1337) onRequestRespond: [ :request | ZnResponse ok: (ZnEntity with: request contents) ].
Sven
Hi Stef, I don't think that the buzz around NodeJS comes from these samples of code. Yes, it's very easy to starting a project with NodeJS but the interest from NodeJS is that this server extends the usages of Javascript wich becomes an language useable on many platform, many OS for many usages. With Javascript, programmers can write client code in browsers, widgets for desktop computers, shell scripts with Rhino, mobile applications for Android or IOS, ... and now, programmers can write server code for web applications and web services. My two cents Olivier ;-) www.auverlot.fr
Hi guys
apparently people get excited by nodeJS and I would like to know the equivalence of
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res .end('Hello World\n'); }).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/'); To run the server, put the code into a file example.js and execute it with the node program:
% node example.js Server running at http://127.0.0.1:1337/
Here is an example of a simple TCP server which listens on port 1337 and echoes whatever you send it:
var net = require('net'); var server = net.createServer(function (socket) { socket.write("Echo server\r\n"); socket.pipe(socket); });
server.listen(1337, "127.0.0.1");
we should communicate better :)
Stef
On 30 Jun 2011, at 18:01, Olivier Auverlot wrote:
I don't think that the buzz around NodeJS comes from these samples of code. Yes, it's very easy to starting a project with NodeJS but the interest from NodeJS is that this server extends the usages of Javascript wich becomes an language useable on many platform, many OS for many usages. With Javascript, programmers can write client code in browsers, widgets for desktop computers, shell scripts with Rhino, mobile applications for Android or IOS, ... and now, programmers can write server code for web applications and web services.
Both what Olivier writes above and what Norbert writes (asynch support) are correct. Still, all this buzz around JS, Ruby, Python, Java, C#, whatever, is just that, buzz. Smalltalk has been an extremely dynamic binary cross platform language for decades, absorbing all kinds of new stuff. Yes, we can and should learn from other developments, but we should not be blinded by the hype. All these other platforms have their strengths, but many serious faults as well. So far, I haven't seen much that can't be done in Smalltalk in some way. And it is so much more easy, productive, nicer, pleasant, fun to do it in Smalltalk. Sven
Yes I know. Now still we are bad at communication and at marketing what we have. Our community as a whole lacked a vision for so long .... We are trying but it is slow Stef On Jun 30, 2011, at 6:01 PM, Olivier Auverlot wrote:
Hi Stef,
I don't think that the buzz around NodeJS comes from these samples of code. Yes, it's very easy to starting a project with NodeJS but the interest from NodeJS is that this server extends the usages of Javascript wich becomes an language useable on many platform, many OS for many usages. With Javascript, programmers can write client code in browsers, widgets for desktop computers, shell scripts with Rhino, mobile applications for Android or IOS, ... and now, programmers can write server code for web applications and web services.
My two cents
Olivier ;-) www.auverlot.fr
Hi guys
apparently people get excited by nodeJS and I would like to know the equivalence of
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res .end('Hello World\n'); }).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/ '); To run the server, put the code into a file example.js and execute it with the node program:
% node example.js Server running at http://127.0.0.1:1337/
Here is an example of a simple TCP server which listens on port 1337 and echoes whatever you send it:
var net = require('net'); var server = net.createServer(function (socket) { socket.write("Echo server\r\n"); socket.pipe(socket); });
server.listen(1337, "127.0.0.1");
we should communicate better :)
Stef
participants (12)
-
Denis Kudriashov -
Igor Stasenko -
Janko Mivšek -
Julian Fitzell -
Matt Kennedy -
Nick Ager -
Norbert Hartl -
Olivier Auverlot -
Philippe Marschall -
Richard Durr -
Stéphane Ducasse -
Sven Van Caekenberghe