mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
130 lines
6.3 KiB
ReStructuredText
130 lines
6.3 KiB
ReStructuredText
:orphan:
|
|
|
|
.. @raise litre.TestsAreMissing
|
|
|
|
.. warning:: This document was used in planning Swift 1.0; it has not been kept
|
|
up to date and does not describe the current or planned behavior of Swift.
|
|
|
|
Mutable Namespace-Scope Variable Declarations
|
|
=============================================
|
|
|
|
A namespace-scope variable (i.e. a variable not inside a function) is allowed to
|
|
have an initializer, and that initializer is allowed to have side effects.
|
|
Thus, we have to decide how and when the initializer runs.
|
|
|
|
WLOG, lets assume that all namespace-scope variables are mutable (and thus that
|
|
immutable variables are just an optimization of the common case). Given that
|
|
they can have mutable state, they cannot be "global" (in the C sense) because
|
|
then they would be visible across multiple actors. Instead, the only logical
|
|
semantic is for them to be actor-local data ("thread local" in the C sense) of
|
|
some sort.
|
|
|
|
Given that there can be many of these variables in an address space, and very
|
|
few of them may be dynamically used by any particular actor, it doesn't make
|
|
sense to allocate space for all of the variables and run all of the initializers
|
|
for the variables at actor-startup-time. Instead, swift should handle these as
|
|
"actor associated data" (stored in a hashtable that the actor has a pointer to)
|
|
and should be lazily initialized (in the absence of 'top level code', see
|
|
below).
|
|
|
|
This means that if you write code like this (optionally we could require an
|
|
attribute to make it clear that the value is actor local)::
|
|
|
|
func foo(_ a : int) -> int { print(a) return 0 }
|
|
|
|
var x = foo(1)
|
|
var y = foo(2)
|
|
|
|
That the print statements will execute the first time that x or y is used by any
|
|
particular actor.
|
|
|
|
|
|
Top Level Code
|
|
--------------
|
|
|
|
One goal of swift is to provide a very "progressive disclosure" model of writing
|
|
code and learning how to write code. Therefore, it is desirable that someone be
|
|
able to start out with::
|
|
|
|
print("hello world\n")
|
|
|
|
as their first application. This requires that we support "top level code",
|
|
which is code outside any function or other declaration. The counter-example of
|
|
this is java, which requires someone to look at "class foo / public static void
|
|
main String[]...." all of which is non-essential to the problem of writing a
|
|
simple app.
|
|
|
|
Top level code is useful for a number of other things: many scripts written by
|
|
unix hackers (in perl, bourne shell, ruby, etc) are really just simple command
|
|
line apps that may have a few helper functions and some code that runs. While
|
|
not essential, it is a great secondary goal to make these sorts of simple apps
|
|
easy to write in Swift as well.
|
|
|
|
Top-Level code and lazily evaluated variable initializers don't mix well, nor
|
|
does top level code and multiple actors. As such, the logical semantics are:
|
|
|
|
1. Source files are partitioned into two cases: "has TLC" and "has no TLC".
|
|
2. All variables defined in "has no TLC" files are allocated and initialized
|
|
lazily.
|
|
3. Source files that have TLC are each initialized in a deterministic order: The
|
|
dependence graph of domains is respected (lower level domains are initialized
|
|
before dependent ones), and the source files within a domain are initialized
|
|
in some deterministic order (perhaps according to their filename or
|
|
something, TBD).
|
|
4. Within a source file with TLC, the TLC is run top down in deterministic order
|
|
whenever the file's initializer is run. This initializer executes in the
|
|
context of the "first" actor, which is created on behalf of the program by
|
|
the runtime library.
|
|
5. If/when some other actor refers to a variable in a file with TLC, it is
|
|
allocated and initialized lazily just like globals in "has no TLC" files.
|
|
|
|
On "Not Having Headers"
|
|
-----------------------
|
|
|
|
One intentional design decision in swift is to not have header files, even for
|
|
public API. This is a design point like Java, but unlike C or Objective-C.
|
|
Having header files for public API is nice for a couple of reasons:
|
|
|
|
1. You *force* people to think about what they are making public, and the act of
|
|
having to put it into a header makes them think about its fragility and
|
|
duration over time.
|
|
2. Headers are a very convenient place to get an overview of what an API is and
|
|
does. In Java you get all the implementation details of a class mixed in
|
|
with its public API, which makes it very difficult to understand "at a
|
|
glance" what a class does.
|
|
3. Headers are very useful documentation for Objective-C because we ship the
|
|
headers but not the implementation of system classes. This allows "jump to
|
|
definition" to go to the declaration of an API in the header, which is
|
|
conveniently co-located with headerdoc.
|
|
|
|
On the other hand, headers have a number of disadvantages including:
|
|
|
|
1. It is plain code duplication, with all the negative effects of it. It slows
|
|
down development, can get out of synch, makes changing API more difficult,
|
|
etc.
|
|
2. If the prototype and implementation get out of synch, it is caught by the
|
|
compiler, but this isn't true for API comments.
|
|
3. Swift natively won't "need" headers, so we'd have to specifically add this
|
|
capability, making the language more complicated.
|
|
4. The implementation of a framework may not be in swift. If you're talking to
|
|
a C or C++ framework, showing a C or C++ header when "jumping to definition"
|
|
is not particularly helpful. We'd prefer to show you the synthesized API
|
|
that swift code should be using.
|
|
5. In Swift, the implementation of some datatype can be split across different
|
|
files. Forcing all their declarations to be next to each other lexically is
|
|
an arbitrary restriction.
|
|
|
|
To address the disadvantages of not having headers, we think that we should:
|
|
|
|
1. Standardize on a syntax for doc comments, and bake it into the language.
|
|
Mistakes using it should be diagnosed by the compiler. It should be a
|
|
warning for public API to not have comments.
|
|
2. There needs to be an API that dumps out the public interface for a compiled
|
|
module/domain in swift syntax, slicing on a declaration. When used on a
|
|
type, for example, this would show the type definition and the declaration of
|
|
all of the methods on it.
|
|
3. The API dumper should always dump in swift syntax, even when run on a Clang
|
|
C/C++/ObjC module. It should make it very clear what the API maps to in
|
|
swift syntax, so it is obvious how to use it.
|
|
4. Not having headers forces us to have really great tools support/integration.
|