async interface
[1/10] from: rotenca::telvia::it at: 4-Mar-2004 16:33
I should like to define a common (standard) interface for async protocols.
I proposed some time ago an object! style, like the View feel, instead of the
awake function.
What do you think?
---
Ciao
Romano
[2/10] from: antonr:iinet:au at: 5-Mar-2004 16:40
The advantage of that over a single function, I suppose,
is so that you can derive from a standard base
object (or choose from several easy-to-use example objects),
with the four functions [connect read write close] inside.
I would be happy with that, if that was what you were thinking.
Also, I see that the user code would be simpler, since
you wouldn't need to nest your user code in a switch,
and actually, the error handling when error? :state could
become a function too.
Any other benefits to this approach ?
Anton.
[3/10] from: rotenca:telvia:it at: 6-Mar-2004 0:47
Hi Anton,
> The advantage of that over a single function, I suppose,
> is so that you can derive from a standard base
> object (or choose from several easy-to-use example objects),
> with the four functions [connect read write close] inside.
>
> I would be happy with that, if that was what you were thinking.
Yes. To limit namespace confusion, they could be called:
resolve* (?)
connect*
write*
read*
peer-close*
> Also, I see that the user code would be simpler, since
> you wouldn't need to nest your user code in a switch,
> and actually, the error handling when error? :state could
> become a function too.
Another solution could send the read error to the read* function, and so on...
This requires an argument for functions:
read*: func [port value][]
value could be an error!, else none (or something else - for furture
expansions)
But handling errors makes code more complex for every function, perhaps is
better your proposal.
> Any other benefits to this approach ?
A default object, perhaps. User can change only what it needs.
One problem is where to store the object and how to permit the user to set it.
A fast example with the error* and with one argument:
;global word
async-feel: make object! [
error*: func [port err [error!][err]
resolve*: func [port value][false]
connect*: func [port value [false]
write*: func [port value][false]
read*: func [port value][false]
peer-close*: func [port value][close port true]
]
p: make port! [
scheme: 'atcp
;must be used an existing field, like user-data
user-data: make async-feel [
read*: func [port value][ print copy port false]
]
]
and/or
p: open/custom async://abc:3838 [
;open must do make async-feel this-block
async-feel [
read*: func [port value][ print copy port false]
]
]
---
Ciao
Romano
[4/10] from: antonr:iinet:au at: 8-Mar-2004 22:12
Hi Romano,
> Hi Anton,
> > The advantage of that over a single function, I suppose,
<<quoted lines omitted: 9>>
> read*
> peer-close*
Hang on, I'm not sure I like this. Isn't the convention
to add an asterisk to the word when it refers to the default
built-in word? ie. write* = system/words/write
I think either system/schemes or global context should
have some functions added (there is already copy* in global context):
write*, read*, open*, close*, which are defined to
simply point to the global versions.
Then all the scheme handlers can use them without waste.
What were you thinking resolve* would be for ?
> > Also, I see that the user code would be simpler, since
> > you wouldn't need to nest your user code in a switch,
<<quoted lines omitted: 12>>
> One problem is where to store the object and how to permit the
> user to set it.
How about here?:
system/schemes/async/base-feel
Modified feels would be stored in the async port, somewhere...
port/...
err... ok, looks like port/user-data then..
> A fast example with the error* and with one argument:
> ;global word
<<quoted lines omitted: 21>>
> ]
> Romano
Here's my version:
p: make port! [
scheme: 'async
user-data: make system/schemes/async/base-feel [
read: func [port value][print copy* port false]
]
]
Anton.
[5/10] from: g:santilli:tiscalinet:it at: 8-Mar-2004 15:26
Hi Anton,
On Monday, March 8, 2004, 12:12:57 PM, you wrote:
AR> Hang on, I'm not sure I like this. Isn't the convention
AR> to add an asterisk to the word when it refers to the default
AR> built-in word? ie. write* = system/words/write
The simplest way is the opposite (like Romano suggests); this way
is only needed for compatibility (i.e. in schemes etc.).
(This is not just my opinion, it is the way VID accessors work, so
we can assume Carl is headed this way.)
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amiga Group Italia sez. L'Aquila --- SOON: http://www.rebol.it/
[6/10] from: andreas:bolka:gmx at: 9-Mar-2004 15:09
Thursday, March 4, 2004, 4:33:29 PM, Romano wrote:
> I should like to define a common (standard) interface for async
> protocols.
> I proposed some time ago an object! style, like the View feel,
> instead of the awake function.
> What do you think?
Sorry if that's missing the point, but I'm currently using something
like the following in my async:// experiments:
-- snip --
async-handler: context [
; default error handler
on-error: func [ port [port!] error [error!] ] [
print mold disarm error
true
]
; default async event handlers
on-connect: func [ port [port!] ] [ false ]
on-close: func [ port [port!] ] [ attempt [ close port ] true ]
on-read: func [ port [port!] ] [ false ]
on-write: func [ port [port!] ] [ false ]
; default dispatcher
handle: func [ port [port!] state [word! error!] ] [
either error? state [
on-error port state
] [
switch state [
connect [ on-connect port ]
close [ on-close port ]
read [ on-read port ]
write [ on-write port ]
]
]
]
]
-- snap --
The 'handle dispatcher is to smoothly use object!'s based on the above
as 'awake handler.
--
Best regards,
Andreas
[7/10] from: rotenca:telvia:it at: 9-Mar-2004 19:15
Hi Andreas,
> ; default dispatcher
> handle: func [ port [port!] state [word! error!] ] [
<<quoted lines omitted: 13>>
> The 'handle dispatcher is to smoothly use object!'s based on the above
> as 'awake handler.
In my last implementation i used a scheme just like your, a dispatch function
which can be used to call functions in an objects or different functions.
---
Ciao
Romano
[8/10] from: rotenca:telvia:it at: 9-Mar-2004 19:31
Hi Anton,
> What were you thinking resolve* would be for ?
Resolve can be ignored, but resolve can fail, like connect.
I am asking it all that errors are a good thing. I am thinking to use words
instead:
dns-failure
connect-failure
errors could be used only for i/o errors
This makes the multi function approach a lillte too complex, perhaps is better
to use the engage approach?
engage: func [port action value [any-type!]][
switch action [
error [print "an error" probe disarm value true]
dns-failure [true]
connect-failure [print ["number of retry:" value] true]
peer-close [true]
read [print copy port false]
write [print copy port false]
]
]
We are back near to the original awake scheme (also if this function is no
more referenced by port/awake)
> How about here?:
>
> system/schemes/async/base-feel
Protocol ports (in the actual implementation) cannot be extended with new
words.
---
Ciao
Romano
[9/10] from: g:santilli:tiscalinet:it at: 11-Mar-2004 17:17
Hi Romano,
On Tuesday, March 9, 2004, 7:31:35 PM, you wrote:
RPT> dns-failure
RPT> connect-failure
Why not using only one function for all errors?
And, I think the connect event is useful, as you may want to start
sending data when the connection is established and not before
(imagine doing streaming).
RPT> This makes the multi function approach a lillte too complex, perhaps is better
RPT> to use the engage approach?
Personally I prefer multiple functions, the problem is making that
fit into the way ports are... maybe in the future they could have
a feel object instead of the awake function.
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amiga Group Italia sez. L'Aquila --- SOON: http://www.rebol.it/
[10/10] from: rotenca:telvia:it at: 12-Mar-2004 1:26
Hi Gabriele,
> RPT> dns-failure
> RPT> connect-failure
>
> Why not using only one function for all errors?
I do not like to handle errors in rebol. I must disarm the error, check the
right field, know what code/type/id/arg I must find to understand what kind of
error is. Some errors are created by handler, other are real i/o errors, other
was errors and now are words ('close).
We could also create a new class of errors, else some different errors will be
of the same code/type/id:
800/user/message
and can be distinguished only by the arg1 field. For example:
>> probe disarm make error! "read-io aborted"
make object! [
code: 800
type: 'user
id: 'message
arg1: "read-io aborted"
arg2: none
arg3: none
near: [probe disarm make error! "read-io aborted"]
where: none
]
>> probe disarm make error! "write-io aborted"
make object! [
code: 800
type: 'user
id: 'message
arg1: "write-io aborted"
arg2: none
arg3: none
near: [probe disarm make error! "write-io aborted"]
where: none
]
My idea was:
use errors for "real" read-io/write-io errors
use 'close for peer close error
use 'max-retry or 'connect-failure for handler error: "max number of requests"
use 'dns-failure for handler error "can resolve host name"
> And, I think the connect event is useful, as you may want to start
> sending data when the connection is established and not before
> (imagine doing streaming).
the 'connect is not removed: it signals "connection done".
> RPT> This makes the multi function approach a lillte too complex, perhaps is
better
> RPT> to use the engage approach?
>
> Personally I prefer multiple functions, the problem is making that
> fit into the way ports are... maybe in the future they could have
> a feel object instead of the awake function.
I have a mode ;-)
Another solutions it to use the standard awake function with only the port
argument and a field in port/locals to store action or errors.
---
Ciao
Romano
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted