Could OWIN use more static typing?

99 views
Skip to first unread message

Anton Tayanovskyy

unread,
Jun 29, 2011, 9:21:19 PM6/29/11
to .NET HTTP Abstractions, websharpe...@intellifactory.com
Hi,

Are there any plans to update and *improve* the OWIN interface and
spec?

To my eyes, it thoroughly lacks types to express invariants and
instead relies on prose. I particularly question
Dictionary<String,Object>. I also question the complexity of Func<_>
body callback definitions, and the need to handle exceptions
explicitly. All this just leads to confusing paragraphs in the spec
and allows weird use scenarios, some of which are outlawed by the
spec, and others I totally miss the use for.

I come from the F# land and here is how I would do it (as a quick job,
this is probably incorrect and faulty, but might give you an idea):

https://gist.github.com/1055424

Thanks,


Anton


--
Kind Regards,
Anton Tayanovskyy

WebSharper(tm) - type-safe JavaScript in F#
http://intellifactory.com

Jeff Hardy

unread,
Jun 30, 2011, 12:09:44 AM6/30/11
to net-http-a...@googlegroups.com, websharpe...@intellifactory.com
On Wed, Jun 29, 2011 at 6:21 PM, Anton Tayanovskyy
<anton.ta...@gmail.com> wrote:
> Hi,
>
> Are there any plans to update and *improve* the OWIN interface and
> spec?
>
> To my eyes, it thoroughly lacks types to express invariants and
> instead relies on prose. I particularly question
> Dictionary<String,Object>. I also question the complexity of Func<_>
> body callback definitions, and the need to handle exceptions
> explicitly. All this just leads to confusing paragraphs in the spec
> and allows weird use scenarios, some of which are outlawed by the
> spec, and others I totally miss the use for.

The big issue with that is that it requires custom types, which means
an assembly. By using the (admittedly crazy) set of delegates, there
doesn't need to be anything such as Owin.dll.

If the .NET framework allowed identical interfaces to be
interchangeable, this wouldn't be issue. Alas, it doesn't.

- Jeff

Anton Tayanovskyy

unread,
Jun 30, 2011, 8:03:07 AM6/30/11
to net-http-a...@googlegroups.com
Hi Jeff,

I kind of suspected that this is one of the goals, but is the
rationale behind it stated anywhere? What would be a problem with
publishing a shared assembly with the interface types?

> If the .NET framework allowed identical interfaces to be
> interchangeable, this wouldn't be issue. Alas, it doesn't.

If sorely put to it, one can hack an Adapt : 'T1 -> 'T2 with
reflection that would map over structurally identical interfaces..

Anton

--
Kind Regards,
Anton Tayanovskyy

WebSharper™ - type-safe JavaScript in F#
http://intellifactory.com

Anton Tayanovskyy

unread,
Jun 30, 2011, 9:09:07 AM6/30/11
to net-http-a...@googlegroups.com
Hi,

So @grumpydev explained to me that shipping an assembly for OWIN with
two or three interfaces is a serious concern in the community. I do
not understand why would it be the case, but I am leaving that aside
for the moment.

Note that it is easy to show that non-generic nominal types can be
encoded using structural types (tuple, union, function and generics
for recursion). It definitely is a simple exercise to do this
conversion for my proposal code:

https://gist.github.com/1055424#file_fscgi.structural.fs

So, this obstacle removed, can we come back to discussing the typing?

I can live with the Dictionary<String,Object> if it is really that
appealing to the masses, but the delegates are still a problem for me
- it seems that a lot can run amok with it given improper use.

The set of delegates is coupled with a protocol on how to use them,
described in prose. The protocol for the types I outline is simpler:
it is not to use exceptions, and write terminating code - this is what
all of us do every day without thinking.

There's also simplicity. In particular, take cancellation. OWIN calls
for a delegate to handle that. In my design cancellation is trivial:
the host container always has the control, and if it decides to
cancel, it just ceases to iterate the iteratee.

Anton

Grumpydev

unread,
Jun 30, 2011, 9:13:35 AM6/30/11
to net-http-a...@googlegroups.com
If it just stops iterating how does the 'iteratee' know it's stopped, so it can perform any cleanup it needs to, rather than just pausing/running slow (waiting for data etc) ?

Anton Tayanovskyy

unread,
Jun 30, 2011, 9:20:10 AM6/30/11
to net-http-a...@googlegroups.com
Great, this seems to be a valid point. Thanks.

As far as I could understand
http://www.haskell.org/haskellwiki/Iteratee_I/O, the job of
opening/closing file handles and other resources are usually the job
for the iterator, not the iteratee.

Yet I can imagine that in the case of the web application it might
need to do it, too.

I'll play with it more when I have the time and see if it degenerates
to the OWIN interface after all.

--

Grumpydev

unread,
Jun 30, 2011, 9:32:28 AM6/30/11
to net-http-a...@googlegroups.com
If you can stomach the round-and-round-in-circles posts there is a lot of useful discussion on this list .. I'm not saying everything has been thought of, but there have been plenty of discussions :-)

Anton Tayanovskyy

unread,
Jun 30, 2011, 9:33:41 AM6/30/11
to net-http-a...@googlegroups.com
For now, here's a quick fix to my proposal that accounts for
cancellation. I have to turn to other things now but I will try to
read up on this more on the weekend.

Thanks!

--A

Benjamin van der Veen

unread,
Jun 30, 2011, 1:59:37 PM6/30/11
to net-http-a...@googlegroups.com
On Wed, Jun 29, 2011 at 6:21 PM, Anton Tayanovskyy <anton.ta...@gmail.com> wrote:
To my eyes, it thoroughly lacks types to express invariants and
instead relies on prose. I particularly question
Dictionary<String,Object>. I also question the complexity of Func<_>
body callback definitions,

Hi Anton,

The decision to avoid declaring concrete types was made so that the spec does not have to be embodied by a DLL library. This way, there doesn't have to be a 'canonical' OWIN.dll, which would be inherently biased toward a particular CLR language. See the last paragraph in the spec overview (http://owin.org/spec#Overview) and also this blog post (http://bvanderveen.com/a/owin-as-csharp-interfaces/)


I come from the F# land and here is how I would do it (as a quick job,
this is probably incorrect and faulty, but might give you an idea):

https://gist.github.com/1055424

Just glancing over it, this looks nearly equivalent to OWIN. It should be trivial to write some glue that would adapt an OWIN interface into this F# one. Again, this is by design. If one were to write an OWIN-compatible web framework or library, of course he would want to provide his own native/idiomatic/(possibly strongly-typed) abstractions in the target language. OWIN is meant to be flexible enough for framework implementors to remain OWIN-compatible and expose that interface in natural way for their target language.

Anton Tayanovskyy

unread,
Jun 30, 2011, 3:16:06 PM6/30/11
to net-http-a...@googlegroups.com
Hi Benjamin,

Thank you for re-stating the rationale behind OWIN decisions for me. I
understand now, even though I might have different priorities.

I also agree that if I can provide a bijection between OWIN and
whatever-I-want then OWIN is in a good place.

However, it is not clear to me just yet whether OWIN is indeed excatly
equivalent to what I have in mind. To me it seems that it is currently
less restrictive, so that I can definitely go FSCGI -> OWIN but not
easily the other way around. I need more time to understand this.

Besides the CPS protocol that OWIN has to trust the applications to
observe (call-only-one-callback-once), another area that seems
troubling to me is the complete asynchrony and symmetry between the
Host and the App in how they stream data. Now the App may yield data
asynchronously as well, whereas alternative designs could force the
App to return on the stack. Perhaps the difference is that OWIN does
not isolate the App-induced asynchrony (such as the application
deciding to open a client socket to another website and read it before
responding) from Host-asynchrony (dealing with concurrent request) and
the scheduler has to serve both of them. There might be non-negligible
performance implications.

Thanks,

Anton

--
Kind Regards,
Anton Tayanovskyy

WebSharper™ - type-safe JavaScript in F#
http://intellifactory.com

Benjamin van der Veen

unread,
Jul 1, 2011, 4:14:15 AM7/1/11
to net-http-a...@googlegroups.com

On Jun 30, 2011, at 12:16, Anton Tayanovskyy <anton.ta...@gmail.com> wrote:
> Besides the CPS protocol that OWIN has to trust the applications to
> observe (call-only-one-callback-once), another area that seems
> troubling to me is the complete asynchrony and symmetry between the
> Host and the App in how they stream data. Now the App may yield data
> asynchronously as well, whereas alternative designs could force the
> App to return on the stack. Perhaps the difference is that OWIN does
> not isolate the App-induced asynchrony (such as the application
> deciding to open a client socket to another website and read it before
> responding) from Host-asynchrony (dealing with concurrent request) and
> the scheduler has to serve both of them. There might be non-negligible
> performance implications.

Not sure I fully follow your thinking here. Could you elaborate or provide an example scenario?

>

Anton Tayanovskyy

unread,
Jul 1, 2011, 5:52:40 PM7/1/11
to net-http-a...@googlegroups.com
Hi again,

Apologies, I realize now I do not know what I am talking about. Please
disregard for now, I need to read up more and experiment.

Intuitively I am suspicious of the fact that OWIN allows the
application to return data asynchronously, but I do not know enough to
say why is that a problem; nor do I know enough to realize it is OK.

Thanks,


Anton

--

Benjamin van der Veen

unread,
Jul 1, 2011, 6:11:56 PM7/1/11
to net-http-a...@googlegroups.com
On Fri, Jul 1, 2011 at 2:52 PM, Anton Tayanovskyy <anton.ta...@gmail.com> wrote:
Intuitively I am suspicious of the fact that OWIN allows the
application to return data asynchronously, but I do not know enough to
say why is that a problem; nor do I know enough to realize it is OK.

Perhaps consider the case when an application is streaming (perhaps from a backend service) a large-ish amount to a slow client (perhaps a mobile device). The underlying transport (TCP) exerts 'back-pressure' on the host (for instance, the mobile device is slow to send ACK packets), so the interface between host and application needs a mechanism to allow that host to exert 'back-pressure' on the application. In a synchronous scenario, a call to write() would block the writing thread. But! We don't want to require a stack to have idle threads sitting around waiting for slow clients. Thus the asynchronous mechanism.

hammett

unread,
Jul 11, 2011, 1:48:31 AM7/11/11
to net-http-a...@googlegroups.com
This decision seems quite dogmatic and hurts more than it helps. I
couldnt care less if I have to embed/distribute a owin.dll with
Monorail, as long it's stable - ie doesnt change. As it is, I just
cant find the willingness to learn what those nested delegates mean..

As for structural type comparison, yes that's _is_ supported in .net
4.0 for interfaces only. Look nopia up. Or see
http://www.infoq.com/news/2008/10/Type-Embedding There was hope that
v.next would support the same for events/exceptions, but I dont think
that will happen.

--
Cheers,
hammett
http://hammett.castleproject.org/

Glenn Block

unread,
Jul 11, 2011, 2:27:30 AM7/11/11
to hammett, net-http-a...@googlegroups.com
Nopia won't help for 3.5 servers. Supporting .net 3.5 was one key goal
which delegates supported.

Sent from my Windows Phone From: hammett
Sent: Sunday, July 10, 2011 10:48 PM
To: net-http-a...@googlegroups.com
Subject: Re: Could OWIN use more static typing?

hammett

unread,
Jul 11, 2011, 3:17:03 AM7/11/11
to net-http-a...@googlegroups.com
That doesn't invalidate my first point.

Anyway, it's your baby. Do whatever you feel is best.

Glenn Block

unread,
Jul 11, 2011, 3:58:01 AM7/11/11
to net-http-a...@googlegroups.com
The first pint is saying that this was a dogmatic decision and hurts more than it helps. In terms of dogmatism, I don't think that was it at all. There was a long back and forth discussion over many weeks on the pros and cons of each approach. Ultimately it was decided that it we did not need to introduce a new binary we shouldn't. 

Gate (dll) however was planned to be the binary that most people most people could/would use though it was not required.

Glenn

Grumpydev

unread,
Jul 11, 2011, 4:06:46 AM7/11/11
to net-http-a...@googlegroups.com
In defence of the Delegate Of Doom (TM) .. it's really not that complicated and doesn't take long to fathom once you start coding with it (although it looks ridiculous when you just look at it). The Nancy implementation took a couple of hours tops, and I was probably slightly drunk at the time ;-)

Benjamin also did an excellent post where he broke it down into component parts and showed the resulting interfaces it would boil down to.

Jeff Hardy

unread,
Jul 11, 2011, 12:08:50 PM7/11/11
to net-http-a...@googlegroups.com

It would be much simpler if it didn't support asynchronous
programming, and also much less useful. I do wonder what OWIN would
look like if 3.5 support was dropped and Owin could use Task and
IObservable instead of delegates.

- Jeff

Louis DeJardin

unread,
Jul 11, 2011, 6:33:17 PM7/11/11
to net-http-a...@googlegroups.com
There was some early experimentation in Taco prototype...

--IObservable--

IObservable seemed to work well and is interchangeable with the body delegate. Concerns with its use revolved around 3.5 support and if a non-.NET class was needed as the payload data type to communicate push-back. Turns out an assembly type isn't needed if you use IObservable<Tuple<byte[],Action,Action>> for pushback.

If there's an appetite for it - it would be very interesting to try using an app-delegate of body-IObservable in a branch in Gate - to see if it's an improvement or a disaster.

--Task--

It seemed Task was fairly awkward to nest/wrap/chain when it was part of the signature... Doable, of course, but some aspects needed a lot of quirky knowledge - like when a task should join parent task, and how exceptions aggregate, and such.

That said - it is fairly straightforward to have Task-based implementations of a delegate or iobservable signature. It's just when the signature has Task that the pipeline glue code got ugly.


-----Original Message-----
From: net-http-a...@googlegroups.com [mailto:net-http-a...@googlegroups.com] On Behalf Of Jeff Hardy
Sent: Monday, July 11, 2011 9:09 AM
To: net-http-a...@googlegroups.com
Subject: Re: Could OWIN use more static typing?

Louis DeJardin

unread,
Aug 15, 2011, 2:50:27 PM8/15/11
to net-http-a...@googlegroups.com
I'm replying to this to follow up on my comment:

> If there's an appetite for it - it would be very interesting to try using an app-delegate of body-IObservable in a branch in Gate - to see if it's an improvement or a disaster.

I went through the exercise locally of changing the body type
From: Func<Func<ArraySegment<byte>, Action, bool>, Action<Exception>, Action, Action>
To: IObservable<Tuple<ArraySegment<byte>, Action, Action>>

It ended up feeling like the observable had enough disadvantages to outweigh the benefits. Here are some things I didn't care for:

* The Tuple instances needed to be created explicitly because Tuple.Create won't recognize Action as a null. The Tuple also has properties named Item1, Item2, Item3 so I occasionally needed to put then in local vars for clarity, or end up testing payload.Item2 != null or calling payload.Item2().

* The calling convention isn't as strict. In terms of representing a "WriteAsync" the bool/continuation are a better fit than pause/resume actions. What I mean is the pause/resume actions would probably be used incorrectly much more frequently because they look like they control a throttle state. Now - I can understand why you would want a throttle state - but you wouldn't implement it in the context of each method call.

* Creating lots of observables. Not that the overhead for creating a featherweight object is a concern - but creating them and the helpers are all extra code. Using IObservable essentially requires you to use a helper implementation of the interface at each point that you're producing or filtering the body, but in the functional signature that same need is accomplished with a closure over local variables.

So yeah - in a nutshell I found that IObservable didn't eliminate any code - but it did end up requiring more helper code and extension methods to make its usage work inline as well as the func did.

Something else occurred to me as well - one advantage to IObservable is that it's a great vehicle for extension methods - but you could do the same thing on the function signature. It's distinct enough I don't think you would get any conflicts. So even if the body is a large Func an extension method could still let you write:

Task t = body.WriteToStreamAsync(stream);

await body.WriteToStreamAsync(stream);

await body.ForEach(bytes=>{etc});

Reply all
Reply to author
Forward
0 new messages