[swift-server-dev] [HTTP] Value vs Reference Types
Samuel Kallner
KALLNER at il.ibm.com
Mon Dec 12 07:45:54 CST 2016
My biggest problem with responses being structs is that it makes it much
harder to have a server in which multiple independent pieces of code need
to run in order for the request to be processed. Why is this useful? It's
nice to have all sorts of things that "annotate" the Request and the
Response, such as Session support, Compression support, Authentication
support, and others.
If one's handlers, as in the example in Ben's e-mail are designed to
simply return a Response struct, the only way subsequent handlers can
modify the response is by wrapping the call to the next handler in the
chain, creating a new response based on the response received, and
returning this new response.
This causes one of two things.
1. There are two types of handlers, one type that simply gets invoked
and returns a Response struct and a second type that gets a
chain to invoke the next handler in the chain.
2. The nice and clean API in the example needs to be changed. And one
always needs to deal with the results of the chain......
The problem I have is that it seems to be a very artificial need for two
different types of handlers. You also then need an opinionated definition
of when each kind of handler runs.
To me things become much simpler if there is a chain of handlers that need
to be run, with simple straight forward order. To do that I believe Both
the Request and the Response need to be reference types.
Shmuel Kallner
STSM Smart Client Platforms group
Tel: +972-4829-6430
e-mail: kallner at il.ibm.com
From: Chris Bailey via swift-server-dev <swift-server-dev at swift.org>
To: Ben Cohen <ben_cohen at apple.com>
Cc: "swift-server-dev at swift.org" <swift-server-dev at swift.org>
Date: 12/12/2016 14:11
Subject: Re: [swift-server-dev] [HTTP] Value vs Reference Types
Sent by: swift-server-dev-bounces at swift.org
Thanks Ben. This is really useful.
Its probably worth also adding some information on the approach taken by
Foundation today for URLRequest/Response.
For outbound requests, Foundation provides both NSURLRequest (class) and
URLRequest (struct). In the case of URLRequest (struct), there is a mix of
types as it contains a getter that returns a stream class for the body -
and the with a number of warnings commented in the code:
"The stream is returned for examination only; it is not safe for
the caller to manipulate the stream in any way"
(
https://github.com/apple/swift-corelibs-foundation/blob/5ab46791996cb65079d02f98115cef6562d4819b/Foundation/URLRequest.swift#L187
)
This is presumably because you shouldn't need to modify the stream for an
outbound request
For responses from outbound requests, only NSURLResponse (class) is
provided as the body is read from the stream.
This effectively give us a model where:
outbound can be a struct (you shouldn't need to touch the
stream)
inbound class (reading from stream)
For the server case, we need the mirror opposite of this - with incoming
requests being a class and the outgoing response potentially being a
struct.
This leads to two questions:
1. Do we think the Foundation model is correct?
2. Do we think it would be confusing to switch been classes and structs
when working with inbound vs. outbound requests, or do we think it would
enforce correct behaviour?
Chris
From: Ben Cohen via swift-server-dev <swift-server-dev at swift.org>
To: Dan Appel <dan.appel00 at gmail.com>
Cc: "swift-server-dev at swift.org" <swift-server-dev at swift.org>
Date: 08/12/2016 02:04
Subject: Re: [swift-server-dev] [HTTP] Value vs Reference Types
Sent by: swift-server-dev-bounces at swift.org
Hi Dan,
Thanks for spelling out these questions, I think they are a great starting
point for a discussion. A few comments inline.
On Nov 23, 2016, at 1:19 PM, Dan Appel via swift-server-dev <
swift-server-dev at swift.org> wrote:
My own responses:
>1. Do we want to use concrete types or protocols for Request/Response?
When working on Open Swift, this was a hot topic since we believed that it
would be unsafe to have a protocol that would allow both value and
reference types.
Bear in mind that a protocol is more than just the methods and types it
declares ? it is also its documentation. For example, a number of
protocols in the standard library state things like complexity
requirements in their documenting comments. The language has no way of
enforcing these, but your type does not truly ?conform? to the protocol
unless you adhere to them. Value semantics are similar ? you can document
that it is invalid to implement a protocol with reference semantics. So I
don?t think this is a blocker to wanting to use protocols.
We arrived upon the `{Request|Response}Representable` pattern which worked
but was a bit of a mess. Because of this, I would prefer concrete
Request/Response types.
You could think of there as being 3 purposes to using protocols here,
roughly in order of importance:
being able to write generic code
allowing different frameworks to interoperate
documenting what you need to implement
The first one is the only reason why a protocol must be included in a
library, and the key question to ask when considering defining a protocol
like this is ?What common algorithms do you want to write across multiple
different conforming types in your program?? (such as generic functions,
including protocol extensions, or functions that take an existential if
the protocol has no associated types).
This is distinct from wanting to be able to be able to choose from
different library implementations of Request. You might want to choose
between the Acme Inc Web Framework?s Request type, or some Swift-Server
?official" Request type, but you never need to use both at once and write
code spanning them. You just want to make sure that one can serve as a
source-compatible ?drop-in? replacement for the other in your code. This
doesn?t mean you can?t write your own extensions ? but you would extend
the concrete Request not a RequestRepresentable protocol.
Next, it?s possible that there might be a collection of 3rd-party
frameworks out there that don?t define Request, but want to be able to
write methods that take or extend multiple possible Request
implementations. This seems a bit unlikely in the case of these types,
more likely in other cases like networking, so it?s kind of a what-if
scenario where there are both multiple popular implementations of Request,
and various frameworks that want to interact with them. Anyone can add a
conformance to anything, so those frameworks can define a protocol of
their own with a subset of the functionality they need, and then just
extend the popular implementations to conform to it. If this gets really
common, at that point it might be worth creating an official protocol for
everyone to share ? but this can be done later, doesn?t have to be done
up-front.
Finally, if you do expect multiple implementations and want people to be
able to swap them in and out when they choose, the protocol can serve to
document what methods and properties you are expected to implement to be
?source compatible". This can be done in documentation instead, the
benefit of the protocol being it helps the library developer ensure
they?ve got all the signatures right etc. But this isn?t something you
expose to users, it?s something on the side to help implementors.
Based on all the above, it seems like there isn?t a pressing need for a
protocol for these types right now and initial designs should focus on a
concrete implementation until one emerges, if only to avoid premature
generalization. Useful protocols tend to be discovered, rather than
designed, through a desire to share common operations on different
concrete types.
>2. If we use concrete types, do we want value or reference semantics?
What I think makes this easier is that the "big four" have each taken a
slightly different approach that can be used as a reference.
Zewo - struct, value semantics
Vapor - closed class, reference semantics
Kitura - closed class + has-a pattern, reference semantics
Perfect - class protocol, reference semantics
Zewo is the outlier here, but I would like to note as a contributor to
Zewo that we have not ran into situations where value semantics create an
impassable roadblock.
To me, it makes sense to pass them around as values since they don't have
any logic of their own. Requests/Responses can't send themselves, they can
only read and modified. It also gives me as a user more safety to pass
them around since I know that they won't be modified implicitly.
Take the following pseudo-code as an example:
HTTPServer.onRequest { request in
print(request.sourceIp)
HTTPClient.send(request)
print(request.sourceIp)
}
With reference semantics, there is no guarantee that sourceIp will be the
same before and after sending off the request. After all, it could make
sense for the HTTPClient to modify the sourceIp before sending off the
request. This of course a contrived example, but the point stands.
Not contrived at all, this is a perfect illustration of why reference
semantics make it harder to reason about your code and identify the cause
of bugs.
Anyway, I think it would be great if we could have people talk about their
own experiences.
>3. When is it more convenient to have reference semantics?
Convenience is a double-edged thing. Pointers with possibly-null values,
or integer indexes into Unicode strings, are often considered convenient.
But that convenience comes with a hidden cost to correctness ? unexpected
nulls, accidentally indexing into the middle of a grapheme cluster etc.
When making a proper effort to handle these things correctly, code quickly
becomes less convenient, and less readable, compared to the alternatives.
It?s generally the style in Swift that correctness shouldn't be sacrificed
for convenience, but when things work out well, convenience and ergonomics
can be mutually reinforcing ? the code is nice to use correctly, awkward
to use incorrectly. For example, optionals that force you to handle nil
help with correctness, but they have sugar like ?? or optional chaining to
handle common patterns clearly and idiomatically, ! as a shorthand for
asserting something is non-nil etc.
In the middleware chain architecture that we decided on in Zewo (the other
ones have something similar), it can be convenient to modify requests in
the responder and have that reflect in the middleware. I think this
problem is best solved with `inout` parameters rather than reference
types, but that is my personal opinion.
FWIW, this design view is also strongly held by those of us working on the
Swift Standard Library. I also brought this up with several members of the
Core Team and they also strongly felt that inout and value types was the
general approach we should take with such types in Swift. The consensus
there was that reference types really should be mostly used when identity
of the value is important.
>4. Are there problems that can't be solved with value semantics?
I haven't found any, but I'm sure others can bring something interesting
to the table.
Shared mutable state is one. With an unavoidably-shared resource, like a
network connection or a handle to a window on a screen, reference
semantics are often what you want.
On Wed, Nov 23, 2016 at 1:07 PM Dan Appel <dan.appel00 at gmail.com> wrote:
Hello everyone!
I was unable to make the kick-off meeting for the HTTP sub-team, but I
looked over the meeting notes and found some topics that I think could use
some more on-the-record discussion.
A few questions that I wanted to raise:
1. Do we want to use concrete types or protocols for Request/Response?
2. If we use concrete types, do we want value or reference semantics?
3. When is it more convenient to have reference semantics?
4. Are there problems that can't be solved with value semantics?
I would like to avoid bike-shedding, and I think this can be done by
providing real examples rather than just talking about the pros and cons.
--
Dan Appel
--
Dan Appel
_______________________________________________
swift-server-dev mailing list
swift-server-dev at swift.org
https://lists.swift.org/mailman/listinfo/swift-server-dev
_______________________________________________
swift-server-dev mailing list
swift-server-dev at swift.org
https://lists.swift.org/mailman/listinfo/swift-server-dev
Unless stated otherwise above:
IBM United Kingdom Limited - Registered in England and Wales with number
741598.
Registered office: PO Box 41, North Harbour, Portsmouth, Hampshire PO6 3AU
_______________________________________________
swift-server-dev mailing list
swift-server-dev at swift.org
https://lists.swift.org/mailman/listinfo/swift-server-dev
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-server-dev/attachments/20161212/52faeb86/attachment.html>
More information about the swift-server-dev
mailing list