Here's another one, hopefully with a little more grounding than the debug test.
I welcome feedback both positive and critical, -- E
Adding an Build Configuration Import Test
Proposal: SE-00XX
Author(s): Erica Sadun <http://github.com/erica>
Status: TBD
Review manager: TBD
<https://gist.github.com/erica/b7f4226b8201945602f2#introduction>Introduction
Expanding the build configuration suite to test for the ability to import
certain modules was first introduced
<http://article.gmane.org/gmane.comp.lang.swift.evolution/7516/match=darwin> on
the Swift-Evolution list by Kevin Ballard. Although his initial idea (checking
for Darwin to differentiate Apple targets from non-Apple targets) proved
problematic, developers warmly greeted the notion of an import-based
configuration test. Dmitri Gribenko wrote, "There's a direction that we want to
move to a unified name for the libc module for all platform, so 'can import
Darwin' might not be a viable long-term strategy." Testing for imports offers
advantages that stand apart from this one use-case: to test for API
availability before use.
<https://gist.github.com/erica/b7f4226b8201945602f2#motivation>Motivation
Swift's existing set of build configurations specify platform differences, not
module commonalities. For example, UIKit enables you to write view code
supported on both iOS and tvOS. SpriteKit allows common code to render on OS X,
iOS, and tvOS that would require an alternate UI on Linux. Testing for Metal
support or Media Player would guard code that will not function on the
simulator. If the simulator adopted these modules at some future time, the code
would naturally expand to provide compatible execution without source
modification.
#if canImport(UIKit)
// UIKit-based code
#elseif canImport(Cocoa)
// OSX code
#elseif
// Workaround/text, whatever
#endif
Guarding code with operating system tests can be less future-proofed than
testing for module support. Excluding OS X to use UIColor creates code that
might eventually find its way to a Linux plaform. Targeting Apple platforms by
inverting a test for Linux essentially broke after the introduction of Windows
and FreeBSD build configurations:
// Exclusive os tests are brittle
#if !os(Linux)
// Matches OSX, iOS, watchOS, tvOS, Windows, FreeBSD
#endif
Inclusive OS tests (if os1 || os2 || os3...) must be audited each time the set
of possible platforms expands. In addition, compound build statements are
harder to write, to validate, and are more confusing to read. They are more
prone to errors than a single test that's tied to the API capabilities used by
the code it guards.
Evan Maloney writes, "Being able to test for the importability of a given
module/framework at runtime would be extremely helpful. We use several
frameworks that are only available in a subset of the platforms we support, and
on only certain OS versions. To work around this problem now, we dynamically
load frameworks from Obj-C only when we're running on an OS version we know is
supported by the framework(s) in question. We can't dynamically load them from
Swift because if they're included in an import, the runtime tries to load it
right away, leading to a crash on any unsupported platform. The only way to
selectively load dynamic frameworks at runtime is to do it via Obj-C. Some sort
of check like the ones you propose should let us avoid this."
<https://gist.github.com/erica/b7f4226b8201945602f2#detail-design>Detail Design
#if canImport(module-name) tests for module support by name. My proposed name
uses lower camelCase, which is not currently used in the current build
configuration vocabulary but is (in my opinion) clearer in intention than the
other two terms brought up on the evolution list, #if imports() and #if
supports().
This build configuration does not import the module it names
This build configuration is intended to differentiate API access
This build configuration should not be used to differentiate platforms
The supplied module token is an arbitrary string. It does not belong to an
enumerated set of known members as this configuration test is intended for use
with both first and third party modules for the greatest flexibility. At
compile time, Swift determines whether the module can or cannot be linked and
builds accordingly.
#if canImport(module)
import module
// use module APIs safely
#endif
#if canImport(module)
// provide solution with module APIs
#else
// provide alternative solution that does not depend on that module
#endif
<https://gist.github.com/erica/b7f4226b8201945602f2#current-art>Current Art
Swift currently supports the following configuration tests:
The literals true and false
The os() function that tests for OSX, iOS, watchOS, tvOS, Linux, Windows, and
FreeBSD
The arch() function that tests for x86_64, arm, arm64, i386, powerpc64, and
powerpc64le
The swift() function that tests for specific Swift language releases, e.g.
swift(>=2.2)
<https://gist.github.com/erica/b7f4226b8201945602f2#alternatives-considered>Alternatives
Considered
There are no alternatives considered._______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution