While researching for my posts about đťś‹ in the Mandelbrot set, I came across a very concise Mandelbrot-plotting program in the Julia language.

``````function mandelbrot(a)
z = 0
for i=1:50
z = z^2 + a
end
return z
end

for y=1.0:-0.05:-1.0
for x=-2.0:0.0315:0.5
abs(mandelbrot(complex(x, y))) < 2 ? print("*") : print(" ")
end
println()
end
``````

Thatâ€™s 235 characters, including the four-space-per-level indents. To use a modern metric of concision, itâ€™s tweetable!

Iâ€™ve been wondering ever since what the minimum idiomatic Swift Mandelbrot-plotting program might be. Hereâ€™s what Iâ€™ve come up with so far:

``````import Numerics

typealias Z = Complex<Double>

for i in stride(from: 1.0, through: -1.0, by: -0.05) {
for r in stride(from: -2.0, through: 0.5, by: 0.0315) {
sequence(first: Z(0, 0)) { z in
z*z + Z(r, i)
}
.prefix(51)
.allSatisfy { \$0.length <= 2 } ?
print("*", terminator: "")
: print(" ", terminator: "")
}
print()
}
``````

339 charactersâ€”and as you may have noticed, thatâ€™s after cheating by using tabs for indentation. Not tweetable.

Hereâ€™s the output, because who doesnâ€™t want to see a Mandelbrot set plot?

``````

**
******
********
******
******** **   *
***   *****************
************************  ***
****************************
******************************
******************************
************************************
*         **********************************
** ***** *     **********************************
***********   ************************************
************** ************************************
***************************************************
*****************************************************
***********************************************************************
*****************************************************
***************************************************
************** ************************************
***********   ************************************
** ***** *     **********************************
*         **********************************
************************************
******************************
******************************
****************************
************************  ***
***   *****************
******** **   *
******
********
******
**

``````

This program has the same basic design as the plotter I built here, but conserves characters by eschewing custom sequence and plot-points types in favor of Standard Library methods. `stride(from:through:by:)` iterates over the real (`r`) and imaginary (`i`) parts of the complex plane where the set lives, and `sequence(first:next:)` is a wonderfully concise way to iterate the complex function whose behavior defines the set.

For each complex point `Z[r, i]`, we plot a `"*"` if the function is still bounded after 50 iterations; otherwise, we plot a space. The Julia implementation iterates the function call 50 times, so we examine the first 51 elements in the sequence, since `sequence(first:next:)` gives the value passed in the parameter `first` as the first element of the sequence, before continuing with the values obtained by iterating the function call.

The boundedness check is accomplished using `allSatisfy(_:)` to determine whether all 50 initial function values in the sequence have a magnitudeâ€”a `length`â€”no greater than 2.

Swift is clearly more verbose than Julia, but Iâ€™m quite happy with that in general. Swift reads more like prose, which in this case increases the possibility that someone whoâ€™s not familiar with the Mandelbrot set might learn how it works. Julia reads more like a domain-specific language for mathematics. Which is great! I think thatâ€™s one of its goals.1 If youâ€™re already comfortable with the jargon and notational conventions of mathematics, Julia lets you translate your mathematical ideas into code very efficiently.

I think Juliaâ€™s biggest advantage over Swift in this test of terseness is its compact stride syntax:

``````for y=1.0:-0.05:-1.0
for x=-2.0:0.0315:0.5
``````

versus Swiftâ€™s

``````for i in stride(from: 1.0, through: -1.0, by: -0.04) {
for r in stride(from: -2.0, through: 0.5, by: 0.02) {
``````

But upon first encountering Juliaâ€™s stride syntax, it wasnâ€™t immediately clear to me what it meant. I mean, not immediately immediatelyâ€”it required a double take, but I figured it out without having to read the docs. Itâ€™s a greater degree of encoding than Swiftâ€™s `stride(from:through:by)`, but once you decode it, you can read and type it very efficiently.

Swift has its own compact syntax for its open- and closed-ended range types, which can be used to implement pithier, but still very readable stride functions.

``````func stride<T>(_ range: ClosedRange<T>, by strideParam: T.Stride) -> StrideThrough<T> where T: Strideable {
stride(from: range.lowerBound, through: range.upperBound, by: strideParam)
}

func stride<T>(_ range: Range<T>, by strideParam: T.Stride) -> StrideTo<T> where T: Strideable {
stride(from: range.lowerBound, to: range.upperBound, by: strideParam)
}
``````

So in the alternate timeline where those are already part of the Standard Library, our minimum Mandelbrot plotter reduces to this:

``````import Numerics

typealias Z = Complex<Double>

for i in stride(-1.0...1.0, by: 0.05) {
for r in stride(-2.0...0.5, by: 0.0315) {
sequence(first: Z(0, 0)) { z in
z*z + Z(r, i)
}
.prefix(51)
.allSatisfy { \$0.length <= 2 } ?
print("*", terminator: "")
: print(" ", terminator: "")
}
print()
}
``````

310 characters, a savings of 29! Weâ€™re getting there! By which I mean the arbitrary goal of tweetability. (Why do I care? I donâ€™t even have a Twitter account.2)

I must confess that in addition to requiring the many worlds interpretation, thereâ€™s another character-conserving cheat here. Since weâ€™re printing in the console without any fancy libraries, we must print rows from top to bottom, which is why the Julia program and the original Swift program stride over the imaginary values â€śbackwardsâ€ť: from greater to lesser values. With `stride(from:through:by:)`, this is done by passing the upper bound as `from` and the lower bound as `through`, and passing a negative value for `by`. But we canâ€™t do that with the slimmer `stride`:

``````for i in stride(1.0...(-1.0), by: -0.05) {
print(i)
}

// -> Fatal error: Can't form Range with upperBound < lowerBound
``````

Even after adding two parenthesis characters to appease the compiler, we get an error at runtime, when it becomes obvious weâ€™ve illegally inverted the relationship of the upper and lower bound members of a `ClosedRange`.

To plot the Mandelbrot set in the conventional complex plane, where imaginary values increase up the vertical axis, weâ€™d have to write the outer loop as

``````for i in stride(-1.0...1.0, by: 0.05).reversed() {
// [...]
}
``````

But that restores 11 of our cleverly-eliminated characters! Thankfully, the Mandelbrot set is symmetric about the horizontal axis, so only a careful reading of the code will reveal that weâ€™ve plotted it upside-down to save characters.

The Swift programâ€™s character count also suffers from Swiftâ€™s lack of a concise expression for printing without a trailing newline. Julia has `print()`, which doesnâ€™t output a newline, and `println()`, which does.

Swift has `print(_:separator:terminator:)`. The first parameter is zero or more things to print. `separator` is the string thatâ€™s interposed between each printed item, and it defaults to `" "`. `terminator` is the string printed after everything else, and it defaults to `"\n"`. Printing without a newline in Swift requires something like

``````print("hello", terminator: "")
``````

Iâ€™m less pleased with this specific case of verbosity. Itâ€™s very flexible, but printing without a newline is common enough when writing a console app that itâ€™s nice to have a quick way to say it. The Julia Mandelbrot plotter needs only

``````print("*") : print(" ")
``````

where Swift requires

``````print("*", terminator: "") : print(" ", terminator: "")
``````

23 vs. 55 characters. More than 55 for Swift, if we wrap the long line containing that fragment.

I havenâ€™t thought of a way to write short-named wrapper functions for `print(_:separator:terminator:)` that isnâ€™t a kludge. A substantial part of the difficulty is finding a trim but not ridiculous way to write â€śprintWithNoTerminatorâ€ť. For now, Iâ€™ll have to invoke yet another alternative timelineâ€”one that forked off from our own much further back in the history of Swift, where it was decided to have separate `print()` and `println()` functions, like Julia. Then we could have the program

``````import Numerics

typealias Z = Complex<Double>

for i in stride(-1.0...1.0, by: 0.05) {
for r in stride(-2.0...0.5, by: 0.0315) {
sequence(first: Z(0, 0)) { z in
z*z + Z(r, i)
}
.prefix(51)
.allSatisfy { \$0.length <= 2 } ? print("*") : print(" ")
}
println()
}
``````

274 characters! Weâ€™ve achieved tweetability! But even if it didnâ€™t require transport to an alternate universe, this is a hollow victory: separate `print()` and `println()` functions donâ€™t seem like idiomatic Swift to me. As verbose as it sometimes is, `print(_:separator:terminator:)` is native Swift. But Iâ€™d love to hear about a more compact, yet still Swifty way to print strings without newlines!

I said at the outset I wanted an idiomatic Swift program. I donâ€™t presume to be the arbiter of the Swift idiom. But a big part of my current thinking about it is that it means using the Standard Library wherever it meets my needs.

I was so smitten by the idea of using `allSatisfy(_:)` on a `Sequence` to test boundedness when I wrote the first đťś‹ in the Mandelbrot set post that I havenâ€™t considered whether there are better alternatives. Iâ€™m starting to have some thoughts about differences between my strategy and that of the Julia program, but thatâ€™s another post.

1. I know very little about Julia beyond this Mandelbrot-plotting program, so I canâ€™t say whether the program Iâ€™ve reproduced here is particularly idiomatic. It is, however, the first program presented when you click the â€śSee Julia Code Examplesâ€ť link on the home page of the official Julia language site. Iâ€™d love to know if an experienced Julia programmer might do it any differently.Â

2. I had a Twitter account, but I deleted it a few years ago, because I was too obsessed with reading everything in my timeline every day, and that included so much toxicity. It was pure consumption on my partâ€”I never tweeted anything. But lately Iâ€™ve been considering that Iâ€™ve gotten a lot of value from the high quality signal that can be strained out of the noise (I read programming-related feeds via the web). And since Iâ€™ve started blogging, I could begin repaying that with my own modest contributions. So maybe?Â