Swift is Open Source

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
6,282
Swift 2.3 to Swift 3 Code Migration

Finally found some free time to tackle converting a Swift 2.3 project to Swift 3 using Xcode 8; the project is a reasonable size project; around ~8500 lines of code, in Objective-C it's line count was closer to ~17000 lines (including headers).

After opening the project in Xcode 8 you are presented with 3 choices:
  • Convert to Swift 3
  • Keep your project in Swift 2.3
  • Postpone the decision until later; i.e. Xcode will prompt you again the next time your open this project in Xcode 8.
Choosing Swift 3, I was presented with the migrator; which presents you with the before and after code in a review window, allowing you to step by by review which lines you would like to Migrator to change and to disable any you don't agree with. This review step took approximately 2 hours, and as far as I could see I agreed with all the changes suggested. The migration completed, and after trying to compile the project I found 12 errors where the migrator had failed; quite surprising that it was so little re it's beta badge.

Fortunately these problems were easily fixed and the project compiled successively i.e. migration of ~8500 lines in under 3 hours; impressive by any measure.

Example of the Migrator:
migrator.jpg

For those that are unfamiliar with what the differences are between Swift 3 and Swift 2.3; let me try to summarise:
  • Swift 3 represents a major overhaul of Swift syntax i.e. many breaking changes
  • Swift 3 also completed a major overhaul of the naming for the iOS, macOS, tvOS and watchOS Cocoa frameworks; making everything feel a bit less verbose and far more Swifty.
  • Stripping of features that were deemed to be unnecessary carry-overs from C, for example c-style for loops, prefix/suffix operators like i++, or --i, etc...
  • Basically the overall goal of Swift 3 was to stabilise the syntax, paving the way for a stable ABI (Application Binary Interface) and enhanced generics implementation.
I'm finding that most of the code I write today is done in Swift, so the change to Swift 3 is a win, well at least for the projects where I can afford to do this. Primarily those running on macOS, iOS will have to wait for the official release of Xcode 8 and Swift 3.

Out of interest I decided to run cloc to see the language split between the code I've written in the last 6 months (probably missed some folders); but as you should agree, Swift is certainly taking the lead here -- I ignore the HTML, as most of that is auto-generated API docs.
Code:
--------------------------------------------------------------------------------
Language                      files          blank        comment           code
--------------------------------------------------------------------------------
HTML                            157           3416              1          91188
Swift                           479          10690          19607          72226
C#                              173           2297           5030          15436
Objective C                      36            843           1233           6901
Go                               29            646            619           5058
Java                             29            418            570           3659
XML                              15              0             90           3290
C                                10            235            589           2923
MSBuild script                   41              0            281           2658
C/C++ Header                     52            420           1250           1907
SQL                              13            243            360           1092
CSS                               5             82            118           1043
Markdown                         17            282              0            773
D                               122             21              0            376
Bourne Shell                      4             21             30            209
XSLT                              1             28              2            202
Python                            2             25              0            164
JSON                              7              0              0            164
WiX source                        1              2             15            106
DOS Batch                         6              7              0             85
YAML                              6              7              1             84
make                              4             23             20             65
JavaScript                        3              5              6             64
XSD                               1              0              0             27
Bourne Again Shell                2             13             14             25
C Shell                           1              4              0             12
--------------------------------------------------------------------------------
SUM:                           1216          19728          29836         199737
--------------------------------------------------------------------------------
The next contenders are C#, Objective-C, Go and Java, which aside from Objective-C probably belong to web service code. Recent advances in Swift server-side coding (re IBM and others) make me fairly confident that even this will migrate to Swift in due course.
 
Last edited:

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
6,282
Swift Open Source Project: Rebuilding NCURSES

In the course of learning Swift (over the last 2 years) I mulled over ideas for an open source project I could tackle in Swift. My decision in the end was to recreate the key functionality of the ncurses library in Swift.

For those unfamiliar with ncurses, here's a short description:
ncurses (new curses) is a programming library that provides an API to assist programmers to write text-based user interfaces in a terminal. Basically it's a toolkit for developing "GUI-like" application software that runs in a terminal.

ncurses was first release 23 years ago; a framework written primarily in C, saw little change over the years, and by today's standards is considered quite difficult to use. Many terminal app programmer's either avoid ncurses entirely or utilise wrappers, for example:
There is quite an extensive list of wrappers available; for just about any language you can think of. The reason for this is primarily due to the complexity of C API; what many wrappers aimed to do was to simplify much of the API, specifically to make it's use more accessible to the target language. The problem however is that ncurses is huge; well over 60,000 lines of code; most of which is C, which doesn't allow for prettiest of APIs.
Code:
---------------------------------------------------------------------------------------
Language                             files          blank        comment           code
---------------------------------------------------------------------------------------
C                                      314           9337          20454          55995
C/C++ Header                            32           1506           2191           5782
C++                                      9            354            410           1936
---------------------------------------------------------------------------------------

The only project (that I'm aware of), who decided not to build another wrapper, but rather to recreate the functionality with a more modern API, is called blessed, built in Javascript, employing a number of modern techniques to simply the API.
The project is fairly popular: >3600 stars, >100 forks -- probably due to the fact that it's API is far easier to use than ncurses.

Goal for pure Swift Framework
In the most basic of terms, the goal for the Swift Framework is to:
  • recreate most of the functionality of ncurses (where it's deemed worthwhile)
  • but with a substantially simpler API
To achieve this goal the project is merging many of techniques employed by ASCII art world, the braille glyph pixels,, ASCII banner fonts (figlet), etc...

Naturally the code needs to be functionally rich, have a simple API, be as lightweight as possible (framework size and memory consumption), and be supported across multiple platforms (macOS, Linux, FreeBSD, etc...). Whilst the intention is to build many feature rich UI elements and some slightly more advanced ones: charting, progress bars, sprites and animation -- the ultimate goal is to hopefully make the framework easily extensible for plugins.

Current Status
Much of the underlying structure has already been developed, screen painting which supports 1bit to 16bit colours (RGB) is quite brisk overall; for the most part it avoids flickering for consecutive paints.

On macOSX Terminal high frame rates (100FPS) are achievable, with complex coloured Ansi renderings.
Whilst the overall frame rate performance is great for medium terminal sizes (120w x 80h); larger full screen views (300w x 100h) still experience moderate flickering. This however will only affect screens where large portions are redrawn; the overall design of the underlying structures, ensures that only the delta changes are rendered during each frame.

The following elements are considered beta ready;
  • TUICharacter - Full color character draw, including braille glyph pixels, and custom rendering: ASCII, Braille Glyph pixels, Blocks, etc. This is a sub part of the TUIView, usually never accessed directly.
  • TUIView: 2D collection of TUICharacter, representing the rendering space of the window, or a custom size specified. This is the standard drawing canvas, and includes many of the draw features one would expect:
    • Pixel
    • Character
    • Text
    • Rich Text
    • Line
    • Rectangle
    • Rounded Rectangle
    • Ellipse, Circle
    • Pie Slice
    • Polygon
    • Star
    • Polyhedron
  • TUIRender: Render customisation i.e. control the colorspace, color composition and render glyphs (ASCII, braille, blocks, ...)
  • Window Borders; Glyph type
  • Xterm Control Codes
    • Color
    • Cursor
    • Line
    • Tab
    • Scroll
    • Delete
    • Window
    • Report (Size, Origin, Cursor, ...)
    • Host Window : Maximise, Minimise, Stack order(raise / lower), Set title, ...
    • Set, ..)
  • Figlet Fonts - 275 tested fonts. Also I created a Xcode 8 beta source editor plugin to render Figlet font title in your code (completely pointless, but just a bit of fun to prove the new tech & the underlying code base.

Next steps:
  1. Progress Bar View
  2. TUIScreen (full screen, multi view rendering)
  3. TUIChart (Line, Bar and Pie)
  4. TUIGauges (donut, etc.)
  5. TUITable (Formatted rendering of structured table data)
  6. TUIImage (Rendering of images: PNG, JPG, GIF, ...)
  7. ... and many more, hopefully useful features..
  8. Oh and before I forget it, Tests i.e. build a complete set of tests. I have quite a bit in my test repo; hopefully will be checking in some of this in the coming week.
In conclusion,
I am building the open source project in my spare time (when I'm not working or studying), but it's a complex build and support would be greatly appreciated; hence I'm extending invitations to anyone who is interesting in joining a new open source project; one that will strengthen your knowledge of:
  • Swift and C
  • Complete your overall understanding of Posix and Xterm related programming
  • Overall User Interface Kit design
Basic Requirements:
  • Working C Programming knowledge, or at least a comfortable ability to read C code; re most of the existing Xterm / Posix reference code resides in either C or C++.
  • Swift: At least a basic understanding of the language or something similar Python, Ruby, C#, ... i.e. you could easily learn as you go
  • Basic knowledge of git and github. i.e. all source will reside on Github
  • Access to either macOS (preferred re Xcode), or alternatively Linux; Apple ensures Swift works on Linux, however Xcode is not available on Linux, so you would have to choose something else e.g. Atom, Appcode CLion, Eclipse, ...
  • Most importantly; spare time to contribute to the project.

Current Code Status
Code:
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Swift                           42            846           2834           4474
C/C++ Header                     2              9              6             12
C                                1              4              6              6
As you can see extensively the repo is Swift, the minor C code is workaround for a current bug with the Darwin stdlib, ioctl and termios TIOC constants on macOS, linux is unaffected.

If however you're just interested to play with the framework; you can download the project here:
https://github.com/AfricanSwift/TUIKit which currently has 3 working demos, and I'll endeavour to add more as features are added, + more will be added once I started work on the project README markdown file.

Here's one of the demos, a reproduction of Apple's WWDC 2016 logo animation in the terminal (slowed down with NSThread.sleepForInterval): https://twitter.com/swiftafricanus/status/745314336126668800

Another example:
This is an example of a 200w x 200h pixel line graphics animation, taking up 100w x 50h characters. Unfortunately the gif can't show the real frame rate. This is however not the best that can be achieved; this render clears the screen buffer completely between redraw commands and paint; an ideal situation for frame rates would paint only the delta between the current paint and the previous one.
TUIKit.gif
 
Last edited:

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
6,282
Swift V3 Update
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160711/024424.html

Hi everyone,

Swift 3 has shaped up to be a remarkable release — a product of the inspiration, ideas, and hard labor many people from across the Swift open source community. It is now time, however, to talk about the endgame for the release.

Here are the key points:

The last day to take planned source-breaking changes for Swift 3 is July 27.

On that day, there will likely be a set of approved-but-not-implemented proposals for Swift 3 — including proposals for source-breaking changes. Will have an open discussion on that day on the fate of those unimplemented proposals in the context of Swift 3 and future Swift releases.

Starting on August 1 we will open up discussion about Swift 4. Part of this discussion will likely be guided by important work that was deferred from Swift 3, as well as the a goal of achieving binary stability in Swift 4. Until then, however, discussion should remain focused on Swift 3.

Note that there is an intentional gap of a few days between the last planned day to take source-breaking changes for Swift 3 and when we start talking about Swift 4. The idea is to provide some time for the community to take stock of where things have ended up for Swift 3.

The final branching plan for Swift 3 development is to be determined, but the final convergence branch is likely to be cut from master around that date or shortly after. Part of it comes down to the discussion on July 27 on how to handle the remaining unimplemented proposals for Swift 3.

The final release date for Swift 3 is TBD, but essentially after July 27 the intent is that Swift 3 is in full convergence and not in active development.

With these dates in mind, I want to call attention to some approved-but-not-yet-implemented proposals that currently I have nobody on Apple's Swift team able to tackle in the next couple weeks:

SE-0042: Flattening the function type of unapplied method references https://github.com/apple/swift-evolution/tree/master/proposals/0042-flatten-method-types.md
SE-0068: Expanding Swift Self to class members and value types https://github.com/apple/swift-evolution/tree/master/proposals/0068-universal-self.md
SE-0075: Adding a Build Configuration Import Test https://github.com/apple/swift-evolution/tree/master/proposals/0075-import-test.md
SE-0096: Converting dynamicType from a property to an operator https://github.com/apple/swift-evolution/tree/master/proposals/0096-dynamictype.md
SE-0077: Improved operator declarations https://github.com/apple/swift-evolution/tree/master/proposals/0077-operator-precedence.md
SE-0092: Typealiases in protocols and protocol extensions https://github.com/apple/swift-evolution/tree/master/proposals/0092-typealiases-in-protocols.md
SE-0110: Distinguish between single-tuple and multiple-argument function types https://github.com/apple/swift-evolution/tree/master/proposals/0110-distingish-single-tuple-arg.md
Some proposals — like SE-0075 https://github.com/apple/swift-evolution/tree/master/proposals/0075-import-test.md — are things we can add at any time, but many of the others tie into the goal of achieving some degree of source-stability for Swift in Swift 3. I'm letting the community know that these proposals currently have no implementation traction in case there is interest in helping make them happen in time for Swift 3.

Related, I'd like to call out a special thanks to the community for getting implementation traction on SE-0095:

SE-0095: Replace protocol<P1,P2> syntax with P1 & P2 syntax https://github.com/apple/swift-evolution/tree/master/proposals/0095-any-as-existential.md
Currently there is a JIRA issue https://bugs.swift.org/browse/SR-1938 and pull request https://github.com/apple/swift/pull/3293 tracking work on implementing this proposal.

In addition to these language proposals, there is also an assortment of outstanding work for the Standard Library that would be great to do for Swift 3. There is a gist summarizing those tasks: https://gist.github.com/gribozavr/37e811f12b27c6365fc88e6f9645634d

These tasks are broken down in relative order of difficulty, with a JIRA issue associated with each one of them. If a JIRA isssue is currently not assigned to anyone, please consider them fair game to tackle if you are interested. API changes that have currently not gone through the evolution process will still need an evolution proposal, even if they are listed in the gist. If you take on a specific task, please assign the JIRA issue to yourself so others know it is being tackled.

Thank you to everyone — and I mean everyone — who has contributed to making Swift 3 happen.

Ted
 

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
6,282
https://www.cocoawithlove.com/blog/2016/07/12/type-checker-issues.html

Excellent article on the complexities of Swift type inference; reasons for the current performance bottlenecks in the type checker and some ideas on what could be done to overcome this.
https://www.cocoawithlove.com/blog/2016/07/12/type-checker-issues.html

Practically a lot of optimization will stay on hold until well after version 3, or at least until full scope Generics, C++ interop and ABI are nearing completion, probably version 4 timeframe (~2017)

If you're interested in more detail on how compiler type inference works, then a good place to start is this book:
Advanced Topics in Types and Programming Languages
 
Last edited:

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
6,282
The following additions have been made to this new framework:
  1. TUIStatus - Configurable progress bar
  2. Braille font (pixel) graphic updates: Replaced previous trig based iterator's with bresenham’s line, circle and ellipse drawing algorithms (faster computation / reduced resource)

Here's a very basic example of how to use the new TUIStatus UI widget:
Code:
var bar1 = TUIStatus(message: "Hello world!")
for i in 1...100
{
  bar1.advance(message: "Hello world! : \(i)")
  Thread.sleep(forTimeInterval: 0.01)
}

Status bars are configured using an array of elements called Bits
Currently the following bits are supported by TUIStatus:
  • percent - % complete
  • message - Status message
  • elasped - Elapsed time in seconds
  • eta - Estimated total duration
  • remaining - Estimated time remaining
  • rate - Current rate of progression per second
  • text - Custom text
  • complete - Complete character sequence
  • incomplete - Incomplete character
  • scan - Scan Activity Indicator
  • cylon - Cylon Activity Indicator (Battlestar Galatica's namesake)
  • animate - Animation Progression Indicator
  • spinner - Spinner Activity and Completion Success / Failure Indicator

These bits provide a versatile way to configure an unlimited variety of status bars, as example the default status bar as shown in the previous code example is internal configiured as follows:
Code:
let format: [TUIStatus.Bits] = [
  .percent,
  .text(" "),
  .complete(sequence: ["⣿"], width: 6, kern: nil),
  .incomplete(filler: "⠶", width: 6, kern: nil),
  .text(" "), .message
]
It's quite simple to recreate a status bar with a custom format; here's a complete example to recreate the previous default status bar.
Code:
let format: [TUIStatus.Bits] = [
  .percent,
  .text(" "),
  .complete(sequence: ["⣿"], width: 6, kern: nil),
  .incomplete(filler: "⠶", width: 6, kern: nil),
  .text(" "), .message
]
var bar1 = TUIStatus(message: "Hello world!")
for i in 1...100
{
  bar1.advance(format: format, message: "Hello world! : \(i)")
  Thread.sleep(forTimeInterval: 0.01)
}

Far more advanced status bit configurations are possible, below is a gif showing four differently configured status bars of varying complexity; the most complex being the third one; the code for which is included below:
TUIStatus.gif
4 examples of the TUIStatus custom configurations.

Code:
let numbers: [Character] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"].reversed()
let spinner: [Character] = TUIStatus.Spinners.runner.characters.map { $0 }
let bellsWhistles: [TUIStatus.Bits] =
  [.percent, .text(" <"),
    .complete(sequence: [""], width: 10, kern: " "),
    .incomplete(filler: "", width: 10, kern: " "),
    .text(" "), .complete(sequence: numbers, width: numbers.count, kern: nil),
    .incomplete(filler: ".", width: numbers.count, kern: nil),
    .text("> "), .remaining,
    .text(" "), .scan(line: "0", filler: "-", width: 3, kern: nil),
    .text(" "), .spinner(sequence: spinner, end: (success: "✔︎", failure: "╳"), kern: " "),
    .text("  "), .animate(sequence: numbers, filler: ".", kern: nil),
    .text(" "), .cylon(eye: "0", filler: "-", width: 3, kern: nil),
    .text(" "), .message]
      
var bar3 = TUIStatus(format: bellsWhistles, message: "Hello world!")
for i in 1...10
{
  bar3.advance(message: "Hello world! : \(i)")
  Thread.sleep(forTimeInterval: 0.01)
  if i > 50
  {
    bar3.failed()
    break
  }
}
Note:
  • The status bar also supports success/failure status; the spinner status bit in particular can be configured to show different a unicode character for success or failure.
  • More details will be added to the project's github readme page (when the project is ready for beta release).

In addition, an example has been added of using colours to enhance some of the figlet fonts
Screen Shot 2016-07-24 at 10.21.35 PM.png

Related Source Code
 
Last edited:

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
6,282
Initial experiment with a bar chart.
Screen Shot 2016-07-26 at 9.24.11 PM.png
 
Last edited:

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
6,282
a String experimentation in futility...

Code:
extension String {
    var p: String {
        return String(self.unicodeScalars.dropLast())
    }
    
    var n: String {
        return String(self.unicodeScalars + [UnicodeScalar(0)])
    }
    
    var l: String {
        return String(self.unicodeScalars.last!)
    }
    
    var d: String {
        return self + l
    }
    
    var b: String {
        return self.p + String(UnicodeScalar(self.unicodeScalars.last!.value + 1))
    }
    
    var m: String {
        return self.p + String(UnicodeScalar(self.unicodeScalars.last!.value - 1))
    }
}

var s = String().n.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.d.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.d.b.b.b.b.b.b.b.d.d.b.b.b.d.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.d.m.m.m.m.m.m.m.m.m.m.m.m.d.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.d.m.m.m.m.m.m.m.m.d.b.b.b.d.m.m.m.m.m.m.d.m.m.m.m.m.m.m.m.d.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m
print(s)

Hello, world!
 

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
6,282
Chris Lattner clattner at apple.com
Fri Jul 29 16:44:29 CDT 2016

Hello Everyone,

### Swift Release Plan ###

Over the next year, the core team expects to ship two major releases of Swift: Swift 3.x in Spring 2017 and Swift 4 in Fall 2017. In addition to the major releases, we will surely ship some minor releases (e.g. Swift 3.0.1) to fix bugs or service the needs of the corelibs or other swift.org http://swift.org/ projects.


### Swift 4 Release Cycle Planning Approach ###

From our experience with Swift 3, we know we need to pick and choose what we’re going to tackle. For Swift 4, the primary goals are to deliver on the promise of source stability from 3.0 on, and to provide ABI stability for the standard library. As such, the core team has decided to take a two-stage approach to the next year:

Stage #1: Focus on the essentials required for Source and ABI stability, and keep reasonably strict focus on only that work. This means that any features that don’t fundamentally change the ABI of existing language features or imply an ABI-breaking change to the standard library will not be considered in this stage. For example, generics features like conditional conformance https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#conditional-conformances- is an additive feature, but since it is expected to reshape much of the standard library it would be part of Stage 1. On the other hand, language support for regular expressions would not affect existing ABI nor cause major changes to existing standard library features, so it would not fit in Stage 1.

The work entailed by Stage 1 is non-trivial (explored in somewhat more detail below), and will probably keep us busy until the Spring.

Stage #2: As the design and implementation work on the Stage 1 features is cresting, we’ll scope and plan a few other large features based on how much time we have left. I’m optimistic that we’ll have time to pick up some of the long list of features explored below, but we won’t know which ones those are until we know how much time we have to develop them with.


In addition to new features, we also need to reevaluate accepted source breaking proposals that didn’t make it into Swift 3. These proposals will not necessarily be grandfathered in - we will need to evaluate them against the goals of Swift 4 and decide what to do with each of them on a case by case basis.

Finally, while it isn’t specifically related to swift-evolution, I want to call out quality & performance work. The core team wants to continue to improve quality, including fixing compiler bugs and improving error and warning diagnostics. Performance is also an ongoing area of critical development, including improving the performance of the generated code, improving the standard library implementation, speeding up compile time, etc. All of this work can happen in either stage.


### Swift 4 Stage 1 Goals ###

With a focus on source and ABI stability, the core team had an initial discussion about what makes up the Stage 1 effort. Here are the features that we are prioritizing for Stage 1:

- Source stability features: These should be relatively small, but important. For example, we need a “-std=swift3” sort of compiler flag. We may also add a way to conditionally enable larger efforts that are under development but not yet stable - in order to make it easier to experiment with them.

- Resilience: This provides a way for public APIs to evolve over time, even in the face of ABI stability. For example, we don’t want the C++ “fragile base class" problem to ever exist in Swift. Much of the design and implementation work was done in the Swift 3 timeframe, but there are still major missing pieces, including the user-visible part of the model (e.g. new attributes).

- ABI Details: There are a ton of small details that should be audited and improved in the code generation model. This is mostly relevant to swift-dev, and not specifically a swift-evolution topic.

- Generics improvements needed by the standard library: I expect conditional conformances https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#conditional-conformances- to be the very top of this list, and for recursive protocol requirements https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#recursive-protocol-constraints- and more powerful associated type constraints to be close followers. However, the standard library gurus need to break down what is absolutely essential to finally eliminate the rest of the “_” protocols and manifest the public API of the standard library in the right way for the long term.

- String re-evaluation: String is one of the most important fundamental types in the language. The standard library leads have numerous ideas of how to improve the programming model for it, without jeopardizing the goals of providing a unicode-correct-by-default model. Our goal is to be better at string processing than Perl!

- Memory ownership model: Adding an (opt-in) Cyclone/Rust inspired memory ownership model to Swift is highly desired by systems programmers and folks who want predictable and deterministic performance (for example, in real time audio processing code). More pertinent to the goals of Swift 4, this feature is important because it fundamentally shapes the ABI. It informs code generation for “inout", how low-level “addressors” work in the ABI, impacts the Swift runtime, and will have a significant impact on the type system and name mangling.

Each of these areas has had some thought put into them already, but are still a long way from being formal proposals. I expect and hope that they will turn into major discussions early in the Swift 4 cycle. Further, since we haven’t fully scoped what impacts ABI stability, there may be other specific additions as we learn more. Finally, it is also possible that we may choose to scope in specific small features that are high value to unblock SwiftPM or other swift.org http://swift.org/ projects.


### Possible Swift 4 Stage 2 Efforts ###

As I mentioned above, at this point it is impossible to know what can be achieved in the Stage 2 timeframe, because we don’t know how long that timeframe is. The core team would also like to converge Swift 4 development earlier in its cycle than Swift 3 did, in order to fix more bugs late in the release and provide a longer bake time.

That said, I’m optimistic that we’ll be able to pick up and tackle some of the commonly requested new features. To give you an idea of some of them, here is a list. Please note that this is not a plan or commitment, it is just a laundry list of commonly requested features:

- Reflection: The core team is committed to adding powerful dynamic features to Swift. For example, Swift 3 already added nearly all the infrastructure for data reflection (which is already used by the Xcode memory debugger). We should use this infrastructure to build out a powerful user-facing API. Similarly, we would like to design and build out the implementation for dynamic method reflection runtime + API support.

- First class concurrency: Actors, async/await, atomicity, memory model, and related topics. This area is highly desired by everyone, as it will open the door for all sorts of new things on the client, server and more. We plan to start formal *discussions* about this in Phase 2, but it is unfortunately crystal clear that a new concurrency model won’t be done in time for the Swift 4 release. This is simply because it will take more than a 12 months to design and build, and we want to make sure to take time to do it right. It also makes sense for the memory ownership model to be better understood before taking this on.

- Generics improvements: The generics manifesto https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md includes many exciting enhancements to the generics system, many of which will not be specifically required for ABI stability of the standard library, but would make Swift generics more powerful and expressive.

- .swiftmodule stability: At some point we need to stabilize the “.swiftmodule” binary file format (or replace it with a different mechanism) to allow 3rd party binary frameworks. This is a very large amount of work over and above what is required for ABI stability of the standard library.

- New scripting features: Regular expressions, multi-line string literals, etc. Having these would make Swift much more appealing to the crowd doing scripting and those building web technologies, among others. They’d also help round out the String model.

- Property behaviors: This feature promises to provide powerful abstractions over the existing property model. The deferred SE-0030 https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md proposal describes this opportunity well.

- So many others: Submodules, implicit promotions between numeric types, importing C++ APIs, hygenic macro system, guaranteed tail calls, making enums enumerable, typed ‘throws’, user defined attributes, abstract methods/classes, better SIMD support, ‘dynamic’ for non- at objc, data parallelism support, higher kinded types, …

- Syntactic sugar: I won’t list them all, but there are a ton of other trivial to small proposals that frequently come up, typically things seen in other languages that solve specific problems. These are the lowest priority to tackle for Swift 4.
 
Last edited:

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
6,282
Terminal UIKit continued...
Charting Update: I've done some experiments with charting; so far I've covered tests with horizontal / vertical bar charts (normal & stacked) and a split pie chart. Whilst I'm fairly happy with the overall look; I'm still not settled on the API's flexibility; hopefully this will be ironed out in a week or two -- I'll share the outcome & code (incl. examples) at that point.

As a bit of digression I decided to look into input state machines and a runloop .
I started toying around with an idea to encapsulate input state using Swift's powerful enum constructs; the idea is to consider the keyboard as two separate state machines running simultaneously: one handles the toggling behavior of the main keypad's caps lock key and its impact on keypad behavior; the other handles the same thing for the numpad + num lock; and a third / four state machine could handle the special keys + mouse.

Here's a rough example in code:
Code:
struct KeyboardState: StateType {
    var mainKeypadState: MainKeypadState
    var numericKeypadState: NumericKeypadState

    enum HardwareKeyEvent {
        // Rough example... missing special keys: CTRL, ALT, ...
        case Alpha(Character)
        case Number(Int)
        case NumLock
        case CapsLock
    }

    static let initialState = KeyboardState(mainKeypadState: MainKeypadState.initialState, numericKeypadState: NumericKeypadState.initialState)

    mutating func handleEvent(event: HardwareKeyEvent) -> KeyboardOutputCommand? {
        if let mainKeypadEvent = MainKeypadState.HardwareKeyEvent(event) {
            return mainKeypadState.handleEvent(mainKeypadEvent)
        } else if let numericKeypadEvent = NumericKeypadState.HardwareKeyEvent(event) {
            return numericKeypadState.handleEvent(numericKeypadEvent)
        } else {
            return nil
        }
    }
}

enum MainKeypadState: StateType {
    case CapsLockOff
    case CapsLockOn

    enum HardwareKeyEvent {
        case Alpha(Character)
        case CapsLock
    }

    static let initialState = MainKeypadState.CapsLockOff

    mutating func handleEvent(event: HardwareKeyEvent) -> KeyboardOutputCommand? {
        switch (self, event) {
        case (.CapsLockOff, .CapsLock):
            self = .CapsLockOn
        case (.CapsLockOff, .Alpha(let c)):
            return .AlphaNumeric(c)

        case (.CapsLockOn, .CapsLock):
            self = .CapsLockOff
        case (.CapsLockOn, .Alpha(let c)):
            return .AlphaNumeric(c.uppercaseCharacter)
        }

        return nil
    }
}

enum NumericKeypadState: StateType {
    case NumLockOff
    case NumLockOn

    enum HardwareKeyEvent {
        case Number(Int)
        case NumLock
    }

    static let initialState = NumericKeypadState.NumLockOn

    mutating func handleEvent(event: HardwareKeyEvent) -> KeyboardOutputCommand? {
        switch (self, event) {
        case (.NumLockOff, .NumLock):
            self = .NumLockOn
        case (.NumLockOff, .Number(let n)):
            if let arrowDirection = ArrowDirection(numericKeypadInput: n) {
                return .Arrow(arrowDirection)
            }

        case (.NumLockOn, .NumLock):
            self = .NumLockOff
        case (.NumLockOn, .Number(let n)):
            return .AlphaNumeric("\(n)".characters.first!)
        }

        return nil
    }
}

enum KeyboardOutputCommand {
    case AlphaNumeric(Character)
    case Arrow(ArrowDirection)
}

enum ArrowDirection {
    case Up, Down, Left, Right
}

extension ArrowDirection {
    // Mapping the numpad keys to arrow keys.
    init?(numericKeypadInput: Int) {
        switch numericKeypadInput {
        case 2: self = .Up
        case 4: self = .Left
        case 6: self = .Right
        case 8: self = .Down
        default: return nil
        }
    }

}

extension MainKeypadState.HardwareKeyEvent {
    init?(_ hardwareKeyEvent: KeyboardState.HardwareKeyEvent) {
        switch hardwareKeyEvent {
        case .Alpha(let c): self = .Alpha(c)
        case .CapsLock: self = .CapsLock
        case .Number, .NumLock: return nil
        }
    }
}

extension NumericKeypadState.HardwareKeyEvent {
    init?(_ hardwareKeyEvent: KeyboardState.HardwareKeyEvent) {
        switch hardwareKeyEvent {
        case .Alpha, .CapsLock: return nil
        case .Number(let n): self = .Number(n)
        case .NumLock: self = .NumLock
        }
    }
}

extension Character {
    var uppercaseCharacter: Character {
        return Character(String(self).uppercaseString)
    }
}

These state machines could be tied into the runloop and event processing i.e. simplify processing of actions associated with the state machine, for example: trapping CTRL-C as an instruction to break out of the app, ...

Next I'll discuss how we tie this into Terminal session.
 
Last edited:

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
6,282
Processing keystrokes and mouse events in a terminal requires a bit of initialization:
  1. We need to instruct the terminal to trap mouse events and define how we want the coordinates to be returned.
  2. Secondly we need instruct the terminal session to switch to non canonical input mode, disable terminal echoing and disable buffering. Basically we need to capture all input; and stop echoing to ensure we don't muck the display and can update our state machines, from which events will be triggered.
Here's an example of code to setup the terminal for non canonical input (byte processing as opposed to line processing), disable echoing / buffering, ... and finally to also ensure that we return the terminal to it's original state at the completion (or crash) of our app (sigaction handler)
Code:
var terminal_descriptor: Int32 = -1
var terminal_original = termios()
var terminal_settings = termios()

/// Restore terminal to original settings
func terminal_done()
{
  if terminal_descriptor != -1
  {
    tcsetattr(terminal_descriptor, TCSANOW, &terminal_original)
  }
}

// "Default" signal handler: restore terminal, then exit.
func terminal_signal(_ signum: Int32)
{
  if terminal_descriptor != -1
  {
    tcsetattr(terminal_descriptor, TCSANOW, &terminal_original)
  }
  
  /* exit() is not async-signal safe, but _exit() is.
   * Use the common idiom of 128 + signal number for signal exits.
   * Alternative approach is to reset the signal to default handler,
   * and immediately raise() it. */
  _exit(128 + signum)
}

  // Initialize terminal for non-canonical, non-echo mode,
  // that should be compatible with standard C I/O.
  // Returns 0 if success, nonzero errno otherwise.
  func terminal_init() -> Int32
  {
    var act = sigaction()
    
    // Already initialized
    if terminal_descriptor != -1
    {
      errno = 0
      return errno
    }
    
    // Which standard stream is connected to our TTY?
    if isatty(STDERR_FILENO) != 0
    {
      terminal_descriptor = STDERR_FILENO
    }
    else if isatty(STDIN_FILENO) != 0
    {
      terminal_descriptor = STDIN_FILENO
    }
    else if isatty(STDOUT_FILENO) != 0
    {
      terminal_descriptor = STDOUT_FILENO
    }
    else
    {
      errno = ENOTTY
      return errno
    }
    
    // Obtain terminal settings.
    if tcgetattr(terminal_descriptor, &terminal_original) != 0 ||
      tcgetattr(terminal_descriptor, &terminal_settings) != 0
    {
      errno = ENOTSUP
      return errno
    }
    
    // Disable buffering for terminal streams.
    if isatty(STDIN_FILENO) != 0
    {
      setvbuf(stdin, nil, _IONBF, 0)
    }
    
    if isatty(STDERR_FILENO) != 0
    {
      setvbuf(stderr, nil, _IONBF, 0)
    }
    
    // At exit() or return from main(), restore the original settings
    if atexit(terminal_done) != 0
    {
      errno = ENOTSUP
      return errno
    }
    
    // Set new "default" handlers for typical signals, so that if this process is
    // killed by a signal, the terminal settings will still be restored first.
    sigemptyset(&act.sa_mask)
    act.__sigaction_u.__sa_handler = terminal_signal as (@convention(c) (Int32) -> Void)
    act.sa_flags = 0
    
    // Break conditions
    var condition = sigaction(SIGHUP,  &act, nil) != 0 ||
      sigaction(SIGINT,  &act, nil) != 0 ||
      sigaction(SIGQUIT, &act, nil) != 0 ||
      sigaction(SIGTERM, &act, nil) != 0 ||
      sigaction(SIGPIPE, &act, nil) != 0 ||
      sigaction(SIGALRM, &act, nil) != 0
    #if SIGXCPU
      condition |= sigaction(SIGXCPU, &act, nil) != 0
    #endif
    #if SIGXFSZ
      condition |= sigaction(SIGXFSZ, &act, nil) != 0
    #endif
    #if SIGIO
      condition |= sigaction(SIGIO, &act, nil) != 0
    #endif

    if condition
    {
      errno = ENOTSUP
      return errno
    }
    
    // Let BREAK cause a SIGINT in input
    terminal_settings.c_iflag &= ~UInt(IGNBRK)
    terminal_settings.c_iflag |=  UInt(BRKINT)
    
    // Ignore framing and parity errors in input
    terminal_settings.c_iflag |=  UInt(IGNPAR)
    terminal_settings.c_iflag &= ~UInt(PARMRK)
    
    // Do not strip eighth bit on input
    terminal_settings.c_iflag &= ~UInt(ISTRIP)
    
    // Do not do newline translation on input
    terminal_settings.c_iflag &= ~(UInt(INLCR) | UInt(IGNCR) | UInt(ICRNL))
    
    #if IUCLC
      // Do not do uppercase-to-lowercase mapping on input
      terminal_settings.c_iflag &= ~UInt(IUCLC)
    #endif
    
    // Use 8-bit characters. This too may affect standard streams,
    // but any sane C library can deal with 8-bit characters
    terminal_settings.c_cflag &= ~UInt(CSIZE)
    terminal_settings.c_cflag |= UInt(CS8)
    
    // Enable receiver
    terminal_settings.c_cflag |= UInt(CREAD)
    
    // Let INTR/QUIT/SUSP/DSUSP generate the corresponding signals
    terminal_settings.c_lflag |= UInt(ISIG)
    
    // Enable noncanonical mode.
    // This is the most important bit, as it disables line buffering etc
    terminal_settings.c_lflag &= ~UInt(ICANON)
    
    // Disable echoing input characters
    terminal_settings.c_lflag &= ~(UInt(ECHO) | UInt(ECHOE) | UInt(ECHOK) | UInt(ECHONL))
    
    // Disable implementation-defined input processing
    terminal_settings.c_lflag &= ~UInt(IEXTEN)
    
    // To maintain best compatibility with normal behaviour of terminals,
    // we set TIME=0 and MAX=1 in noncanonical mode. This means that
    // read() will block until at least one byte is available.
    //  terminal_settings.c_cc[VTIME] = 0
    //  terminal_settings.c_cc[VMIN] = 1
    //
    // Note: this is certainly something we'll need to review i.e. we wouldn't want 
    // to block main thread; because that would imply no screen updates occur
    // without state input. Ideally we'd set VTIME to an acceptable delay; limit 
    // impact to refresh rates.
    Ansi.Terminal.setc_cc(settings: &terminal_settings, index: VTIME, value: 0)
    Ansi.Terminal.setc_cc(settings: &terminal_settings, index: VMIN, value: 1)
    
    // Set the new terminal settings.
    // Note that we don't actually check which ones were successfully
    // set and which not, because there isn't much we can do about it.
    tcsetattr(terminal_descriptor, TCSANOW, &terminal_settings)
    
    // Done
    errno = 0
    return errno
  }

  /// Set termios control chars
  ///
  /// - parameters:
  ///   - settings: inout termios
  ///   - index: Int32
  ///   - value: UInt8
  internal static func setc_cc(settings: inout termios, index: Int32, value: UInt8)
  {
    withUnsafeMutablePointer(&settings.c_cc) { tuplePointer -> Void in
      let c_ccPointer = UnsafeMutablePointer<cc_t>(tuplePointer)
      c_ccPointer[Int(index)] = value
    }
  }

After we reconfigured the terminal session (for non canonical input, ...); we then need to instruct the terminal to insert mouse states into input stream; this is achieved by sending the following ansi instruction the terminal:
  • Activate: <esc>[1000h
  • Deactivate: <esc>[1000l
Note: <esc> is the equivalent of unicode hexadecimal 1B; jointly <esc> & [ are referred to as CSI (Control Sequence Introducer) -- a common prefix character sequence for most ansi control codes (instructions to the terminal). For example: <esc>[31m instructs the terminal to make all the text after the code, RED. Text will stay red until another cancelling or reset code is received; very similar to HTML. everything after the <B> tag appears in bold, until we received the closing tag </B>

Once we've got the terminal into the correct state; we need ensure that we have a process to retrieve this data; without which we'd likely overwhelm (or hang) the terminal session. Processing the data requires two things:
  • A standard runloop to trigger configured events
  • An event to retrieve the input data from standard input (stdin).
Here's a rough example of the code to set up a timed runloop:
Code:
public class RunLoopDelegate
{
  @objc public func run()
  {
    let now = Date()
    print("fired \(now)")
  }
}

var now = Date()
var timer = Timer(fireAt: now, interval: 0.01, target: RunLoopDelegate(),
         selector: #selector(RunLoopDelegate.run), userInfo: nil, repeats: true)

var runLoop = RunLoop.current()
runLoop.add(timer, forMode: .defaultRunLoopMode)
runLoop.run()
...and here's and example of the code to retrieve the input from stdin; this is btw where we'll tie in the update of our state machines.
Code:
  var c: Int32 = getc(stdin)
  
  while c != EOF
  {
    if c >= 33 && c <= 126
    {
      let format = String(format: "0x%02x = 0%03o = %3d = '%c'\n", c, c, c, c)
      print(format)
    }
    else
    {
      let format = String(format: "0x%02x = 0%03o = %3d\n", c, c, c)
      print(format)
    }
    
    // break out for CTRL-C
    if c == 3
    {
      break
    }
    
    c = getc(stdin)
  }
The examples are quite rough around the edges; but hopefully you can make some sense from this.

Here's a bit more details on the terminal controls codes:

And here's some details about runloops (basically they're a loop that keeps the application alive & working): https://developer.apple.com/library...ding/RunLoopManagement/RunLoopManagement.html
 
Last edited:

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
6,282
Xcode tips:
Downloading new and/or beta versions of Xcode can be a bit of pain via the Mac App store (re reliability and install issues). Plus no beta version are available via MAS; you need to download these through a browser. The problem I have with browsers is reliability; they not only crash, are slow to download and in many case don't support proper checkpoint resume.

For better success I suggest you try 2 options:
  • Boris Bügling (@neonichu)'s xcode-install (written in Ruby). Only current proviso is that he is in the process of joining Apple's Xcode team, and Apple contract forbids its employees from continuing with 3rd party and/or open source activities. So although it's a still a good option -- you can't bank on it because in a month it's ongoing support is unknown.
  • Use aria2c in combination with Safari, Google Chrome and the cookies.txt chrome extension:
    1. Login in to http://developer.apple.com/xcode/downloads (you'll need at least a free developer account. note: $99 account is only required for app submission; you can download beta versions and install your apps with the free account.
    2. Click on download Xcode; and immediately stop it; navigate to the folder where the temporary download file was stored: usually ~/Downloads
    3. Right click on the temporary Safari download file; something similar to this: "Xcode_8_beta_4/Xcode_8_beta_4.xip" and choose "Show Package Contents", then open on the info.plist file.
    4. In info.plist; you need to look for the following key "DownloadEntryURL"; this is the full URL to the Xcode download that you clicked on previously.
    5. Now launch Google Chrome, (make sure you installed the Cookies.txt extension), and again login into http://developer.apple.com/xcode/downloads, and click on the download; cancel the download when you're done.
    6. Finally click on the Cookies.txt toolbar icon and click the "click here" option to store your active session cookie in a local file: cookie.txt
    7. At this stage we're finished with Safari and Google Chrome, close these if you no longer need them.
    8. Now Launch a terminal session and change directory to "cd ~/Downloads"
    9. Now we need aria2c; if this hasn't been installed; then first run the following command to install it: "brew install aria2"
    10. Finally make sure you are in the ~/Downloads folder, the same folder that the home extension cookies.txt should have been created.
    11. Here's an example command to perform the download: "aria2c -x5 --load-cookies=cookies.txt http://adcdownload.apple.com/Developer_Tools/Xcode_8_beta_4/Xcode_8_beta_3.xip"
    12. -x5 specifies that the download should be split between 5 threads; you can use more or less. This can substantially speed up the download (depends on your connection speeds)
    13. --load-cookies= species the session cookie for the download; Apple sites only allow download from logged in developer accounts; the session data is stored in a cookie, which the chrome extension allows us to store in a file in the ~/Download folder.
And that's it; Both options work well; Personally I prefer aria2c, because it allows me to resume broken downloads and to increase the download thread count i.e. I'm usually able to cut a typical 4 to 5Gb download time by more than 50%

Note: aria2 is a lightweight multi-protocol & multi-source command-line download utility. It supports HTTP/HTTPS, FTP, SFTP, BitTorrent and Metalink. aria2 can be manipulated via built-in JSON-RPC and XML-RPC interfaces.
 
Last edited:

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
6,282
Terminal UI Kit - Update

Unfortunately in that last period I haven't been able to dedicate as much time to this project as I'd like (work/studies) -- this weekend is however free, and with that I've been able to make some good progress.

Thinking back, I probably needed a break away to overcome some of the blocking issues; funny how issues that previously seemed difficult, are now in hindsight actually quite simple to solve.

I've made the following changes and additions to this project:
1. Removed most of the partial functions; those functions that would work only within a defined value range. These have now been converted to full functions, meaning invalid or out of bounds value are simply ignored (e.g. pixels off screen).
2. Remove the Point(x,y) and replaced it with a vector type: a TUIVec2 struct (x, y)
3. Added 3D vector type; TUIVec3 struct (x,y, z)
4. Added some 2d and 3D vector math to aid in rendering of 2d and 3d models.
5. Added function to draw triangles from 3 vectors (primarily for 3d rendering of models).
6. Added support for Double Width and Double Height Mode (See examples below)

These are the things I'm currently busy with; draft concepts, that appear to be workable and and improvement over the current code:
1. Xterm Control Sequences type: currently called Ansi. The current approach was to append all control sequences together, and then compress the sequences (using a control sequence parser and tokeniser); naturally this approach without compression would tend to generate quite a bit more sequences than was necessary for the render. Compression would resolve most of these issues, but at a cost of computing time and potentially frame rate. The new approach tries to maximise the compression of sequences at the same time that the control sequence command are executed; this is achieving anything between 60% to 80% automatic sequence compression; so whilst it won't completely eliminate the need for compression; it's certainly looking positive -- it affects a huge part of the code (> 2000 lines), so it's going to take quite a bit more time to finish.
2. Color types; Again I've decided to rewrite the colour type because of many inaccuracies with the HSL (Hue, Saturation and Lightness) algorithms, similarly with the CIE Lba colorspace. The problems entailed inaccurate colour render, and in some cases bleached or too dark colours. I've solved this problems, but the write requires a significant change (> 1500 lines) and like the sequences is going to required a bit more time (than this weekend) to finish.
3. I've did a bit of proof of concept work on graphing (lines, bar, stacked bar, pie charts, ...) -- but these are on hold until I finish the Control Sequences and Color changes.
4. Runloops and event handlers; This hasn't changed much since my last post; again postponed until the other work is complete.

New demos:
After adding the new Vector types and the vector math, I decided to enhance the Wavefront wireframe render demo to render a shaded version of the african_head wavefront file using the new drawTriangle function. Here's the first render; I've still got some cleanup to do; e.g. inside of the mouth is currently rendered over the lips, eye cavity, ...
Screen Shot 2016-08-14 at 7.58.52 AM.png
It also renders quite nicely using a ASCII render style (there are current 8 render styles):
Screen Shot 2016-08-14 at 8.00.11 AM.png

Extended Character set (Blocks)
Screen Shot 2016-08-14 at 9.19.27 AM.png

Double Width / Double Height mode example:
This Control Sequence mode, e.g. allows for larger fonts and more visible Emoji
Screen Shot 2016-08-14 at 8.53.03 AM.png

Anyway that's it for now; I'm still going to be working on the code for the rest of the day, but I doubt I'll provide another update before next weekend.

As always if you're looking to try out the code; you can find it on github: https://github.com/AfricanSwift/TUIKit.
 
Last edited:

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
6,282
TUIKit update
Specifically related to the rendering of 3d models in a terminal session. The last set of images I shared had a specific problem; that being that polygons at the back or inside of the models were still being rendered even though they shouldn't be visible.

There are quite a few algorithms (of varying complexity) that can be used to identify and ultimately remove these "backface" polygons before rendering, for example:
  • Backface culling. Discard all triangles where the dot product of their surface normal and the camera-to-triangle vector is greater than or equal to zero.
  • Painter's algorithm also known as a priority fill, is one of the simplest solutions to the visibility problem in 3D computer graphics. When projecting a 3D scene onto a 2D plane, it is necessary at some point to decide which polygons are visible, and which are hidden.
  • Newell's algorithm is a procedure for elimination of polygon cycles in the depth sorting required in hidden surface removal.
  • Z Buffering, also known as depth buffering, is the management of image depth coordinates in 3D graphics.
  • Binary Space Partitioning (BSP) is a method for recursively subdividing a space into convex sets by hyperplanes.
  • Wornock's algorithm. It solves the problem of rendering a complicated image by recursive subdivision of a scene until areas are obtained that are trivial to compute.
  • Scanline algorithm. that works on a row-by-row basis rather than a polygon-by-polygon or pixel-by-pixel basis.
  • Shoelace Algorithm, also known as Gauss's area formula or the surveyor's formula; is a mathematical algorithm to determine the area of a simple polygon whose vertices are described by ordered pairs in the plane.
Whew... I think I covered most of them. I chose to use the Shoelace Algorithm (because it's simple to calculate) in combination with a very rudimentary variation on Z Buffering;
Screen Shot 2016-08-16 at 6.43.29 AM.png
Here's the steps I followed:
  1. Calculate shoelace value for each polygon, keeping only the postive values; the negative values are backfaces.
  2. Sort polygons based on high to low shoelace values, and then basically render the image in reverse (high to low). The idea being that smaller polygons relate to details i.e. to avoid big polygons over painting detail, I simply render the big polygons before the small ones (probably not perfect), but then simulating this in a terminal session isn't either. FYI I tried it with a few other models and the result seems acceptable; time will tell.
Here's the code for shoelace calculation (looks far simpler than it's mathematic formula :)): a,b,c are the three vectors of the triangle.
Code:
public static func shoelace(vector1: TUIVec2, vector2: TUIVec2, vector3: TUIVec2) -> Double
  {
    let a = vector1.x * vector2.y - vector2.x * vector1.y
    let b = vector2.x * vector3.y - vector3.x * vector2.y
    let c = vector2.x * vector1.y - vector1.x * vector2.y
    return (a + b + c) / 2
  }
...and if you wondering why it's called the shoelace algorithm; that because the multiplication and subtraction formula process looks a lot like a shoelace pattern:
Screen Shot 2016-08-16 at 7.21.04 AM.png

Finally here's the images; 1st one is rendered use the braille unicode symbols (simulating pixels), next a full ASCII character set (order by intensity), and lastly block unicode characters (50% to 100% shading).
Wavefront3.png
Wavefront2.png
Wavefront4.png
Anyway that's it for now... Aside from other work I have planned; after this I'm quite interested to see if I can get these models to rotate: pitch, yaw, roll -- well that's the idea anyway; expecting to hit a performance problems (rendering) on this one, but hey that's no reason to not try.
 
Last edited:

_kabal_

Executive Member
Joined
Oct 24, 2005
Messages
5,923
instead of bloating the other FP thread, can you explain the different syntaxes here

Code:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
  .map { $0 * 2 }
  .sorted(by: >)
  .forEach { print($0, terminator: ", ") }

are those curly braces anonymous functions/closures? is that just sugar that you can ommit the opening and closing parenthesis?
just trying to figure out the difference between the call to `map` and `sorted`


Code:
extension Int {
  func increment(by amount: Int) -> Int {
    return self + amount
  }
}

let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
let numbersPlusOne = numbers.map { $0.increment(by: 1) }


how does that "by" syntax work? is that just a named parameter? why would you use or not use this? or is it a swift requirement
 

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
6,282
instead of bloating the other FP thread, can you explain the different syntaxes here

Code:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
  .map { $0 * 2 }
  .sorted(by: >)
  .forEach { print($0, terminator: ", ") }

are those curly braces anonymous functions/closures? is that just sugar that you can ommit the opening and closing parenthesis?
just trying to figure out the difference between the call to `map` and `sorted`
You understood it perfectly; that is just a syntactic sugar variation; they are closures, and in Swift these are by default non escaping, however with the @escaping tag you can change that if you like. Let me start by expanding the syntax, i.e. removing the sugar.
Code:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
  .map({ $0 * 2 })
  .sorted(by: {$0 > $1})
  .forEach({ print($0, terminator: ", ")})

Closures
Basically a closure e.g. `() -> T` or `() -> Void` that is positioned as the last parameter, can be either enclosed in brackets, or simply suffixed as a closure block in curly brackets. Here's an example:
Code:
func reduce(_ initial: Int, _ closure: (Int) -> Int) -> Int { }
Here we have a function that takes two parameters, from the API perspective the parameters names are not required re `_`, this function can be called in two ways, for example:
Code:
reduce(0, {$0 +1 })
...or....
reduce(0) { $0 + 1}
Either way works, however operator `>` syntactic sugar like with `sorted(by` only works if you use the bracketed version without curly braces.

Sorted(by
The `by:` is a named parameter; if Swift named parameter are by default not optional. however to make it optional is easy you simply prefix the named parameter an underscore. For example:
Code:
func increment(_ by: Int) -> Int { }
Now you can call the function without the parameter, e.g. `increment(2)`

Sorted method extraction
Here's an extraction of `sorted(by` in Swift's source code.
Code:
public func sorted(by areInIncreasingOrder: 
   (Iterator.Element, Iterator.Element) -> Bool) -> [Iterator.Element] 
{
   var result = ContiguousArray(self)
   result.sort(by: areInIncreasingOrder)
   return Array(result)
}
As you can see it's API parameter name is `by`, whereas internally it uses `areInIncreasingOrder`, secondly the type of this parameter is `(Iterator.Element, Iterator.Element) -> Bool`, a closure that has two value going in and returns a `Bool`, i.e. typically comparator type. `Iterator.Element` btw is just generic type alias placeholder, it could just as well have been 'banana'. The function is a method in a extension on both `Sequence` and `MutableCollection`, e.g.
Code:
extension Sequence where Self.Iterator.Element : Comparable {
  ... sorted function is included here..
}
As you can also see the Iterator.Element is type constained to `Comparable` i.e. any types we want to sort has to comply with the comparable protocol (interface) i.e. they have to implement type specific operators for `==`, `>`, and `<`

The second purpose of the prefix placeholder is to have a difference between the named parameter (API visible) versus the internal name you use in the function code. i.e. your named parameter can be to used make your function grammatically easier to read, whilst not having to deal with potentially long parameters names internally, for example:
Code:
func move(from start: Point, to end: Point) { }
This would read from the API perspective as `move(from: p1, to: p2)`, but internally you would use `start` and `end`. More detail on how Swift has used this to try and make the API more readable can be found here: https://swift.org/documentation/api-design-guidelines/

Code:
extension Int {
  func increment(by amount: Int) -> Int {
    return self + amount
  }
}

let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
let numbersPlusOne = numbers.map { $0.increment(by: 1) }

how does that "by" syntax work? is that just a named parameter? why would you use or not use this? or is it a swift requirement
As mentioned the `by`word is what the developer sees from the API perspective, where `amount` word is what we use internally, same parameter with two different names.

Anyway thanks for the question... hopefully not too much of a information overload.
 
Last edited:

[)roi(]

Executive Member
Joined
Apr 15, 2005
Messages
6,282
Swift 3.0 Released

Swift 3.0, the first major release of Swift since it was open-sourced, is now officially released! Swift 3 is a huge release containing major improvements and refinements to the core language and Standard Library, major additions to the Linux port of Swift, and the first official release of the Swift Package Manager.
It's an extensive release with many breaking changes; details are here:

You can also find release note here:

And the release download of Xcode8: https://developer.apple.com/xcode/download/
 
Top