[swift-evolution] Swift null safety questions
Elijah Johnson
ejrx7753 at gmail.com
Tue Mar 21 08:27:14 CDT 2017
I still like the idea of shared memory, but since without additional
threading it can’t have write access inside the new process, I don’t think
that it is a solution for a webserver.
The main concern was just with developers using these universal exceptions
deliberately, along with “inconsistent states” and memory leaks.
So here’s a simple proposal:
func unsafeCatchFatalErrorWithMemoryLeak(_ block: ()->Void) -> FatalError?
What it does is execute the block, and when the fatalError function is
invoked (as is the case with logic errors), the fatalError checks some
thread local for the existence of this handler and performs a goto.
“unsafeCatchFatalErrorWithMemoryLeak” then returns a small object with the
error message. The can only be one per-call stack, and it leaks
deliberately leaks the entire stack from “fatalError” back down to
“unsafeCatchFatalErrorWithMemoryLeak”, and that is one reason why it is
labelled “unsafe” and “withMemoryLeak”.
The idea is that this is a function expressly for “high availability”
applications like web servers. The server will now have some leaked objects
posing no immediate danger, and some inconsistencies, primarily or entirely
inside the leaked objects (It is the developer’s responsibility how this is
used).
The “high availability sytem” is then expected to stop accepting incoming
socket connections, generate another instance of itself, handle any open
connections, and exit.
The interesting thing about this is that it is very easy to implement.
Being an unsafe function, it is not part of the language as a catch block
is, and doesn’t entirely preclude another solution in the future.
On March 14, 2017 at 8:22:11 PM, Elijah Johnson (ejrx7753 at gmail.com) wrote:
But - that would require a dedicated thread or a thread pool to run
function calls on. Definitely it lacks many of the advantages of shared
objects directly in the process. I would definitely prefer a small memory
leak or inconsistent state. The server could handle existing requests and
restart itself if it were really an issue. A memory leak can be estimated
and the server restarted after every “x” times, while an inconsistent state
is something that happens in any shared server environment. The developers
just don’t modify the shared state until they have ready the final object,
and their array/dictionary put function call itself isn’t likely to be the
fail that happened.
On March 14, 2017 at 7:29:28 PM, Elijah Johnson (ejrx7753 at gmail.com) wrote:
Also the proxies would need to implement some protocol so that they can be
de-proxied when sent back to a shared method, and the proxy object exposed
to the user with a new declaration that accepts only proxies. Like using
MyClass -> MyClassSharedProxy for the proxy class and
class MyClass {
func testReturnsObject() -> SomeClass
func call(a:MyClass) -> MyClass
}
would become
class MyClassSharedProxy : MyClass, SharedProxyProtocol {
func testReturnsObject() -> SomeClassSharedProxy
func call(a:MyClassSharedProxy) -> MyClassSharedProxy
}
for example.
On March 14, 2017 at 7:15:08 PM, Elijah Johnson (ejrx7753 at gmail.com) wrote:
Sounds like a good idea. I assume that Swift would need to compile these
proxies in advance to be sub-classes ie. binary compatible objects that
will forward calls and return proxies. “Value” types can be copied as they
normally are, or wrapped by the user (along with “final” objects which
could be wrapped manually or made not-final). Then you’d just need a way to
get your first proxy object and a way to register the process’s object.
Something like
func openSharedObject(pid:String) throws -> Any? // cast to expected
value
func registerSharedProxyObject(object:Any) // for this process
I suppose the caller would have to be the one to compile these proxy
objects and locate them in its own module.
The advantage here is that it would be not too difficult for existing
servers to make use of this, as they are already written as a single
process in Swift and so they would just need to manage and pre-fork
processes instead of threads. Seems like it would also have numerous uses
in the systems programming domain.
Then one just needs, ideally, to get a stack trace and fatal error message
to the parent process if a child process crashes.
On March 14, 2017 at 12:18:37 AM, Brent Royal-Gordon (brent at architechies.com)
wrote:
> On Mar 13, 2017, at 5:54 PM, Matthew Johnson <matthew at anandabits.com>
wrote:
>
> I suspect you're right about this for the most part but I think we will
want the ability for "failable processes" (or whatever they're called) to
have read-only access to shared state that outlives them. What I can't
imagine is allowing them write access to state that is shared.
The problem there is that shared data in Swift always has a retain count,
so we'd need some way to track when code in one of these "mini-processes"
retains an external object so we can release it if it crashes. Perhaps
you'd need to wrap a proxy type around shared objects (or instances
containing shared objects, like Array and String) and the proxies would
register themselves with the runtime as needing emergency cleanup beyond
unceremonious deallocation of their "mini-process"'s memory space. This is
all doable; it just needs to be designed and done.
--
Brent Royal-Gordon
Sent from my iPhone
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170321/e0179f19/attachment.html>
More information about the swift-evolution
mailing list