I really dislike the proposed way to do this. If this is "Swifty", give me something else.
The Haskell list comprehension made sense to me the first time I saw it, but there is no way I'd know what the mess in the article was doing until someone explained to me.
Design has to come first. You can't just go with what's "Swifty" if that doesn't convey what's happening in a reasonable fashion.
>The Haskell list comprehension made sense to me the first time I saw it, but there is no way I'd know what the mess in the article was doing until someone explained to me.
Given that this is basic Swift, the complaint makes no sense:
let a = Array(1..<5, 3..<5, where: { n, _ in n % 2 == 0 })
{ ($0, $1) }
// [(2,3),(2,4),(2,5) ...
let a = Array(1..<5, 3..<5) { ($0, $1) }
// [(1,3),(1,4),(1,5),(2,3),(2,4) ...
A list comprehension is basically a cartesian product with a filter and map applied to it.
What we have here is an array constructor, which takes one or more ranges as its arguments. The named `where:` argument provides the filter closure and the final argument is the map, using standard trailing closure syntax.
In fact, other than the missing implementation of the constructor, this would be perfectly legal Swift code today.
I'm not sure what's there to be confused about. `x..<y` describes an open range (including x, excluding y). `{x, y in ... }` is normal Swift closure syntax, where `x` and `y` are the arguments; you can also use positional arguments as in `{ ($0, $1) }` instead.
If the final argument of a function is a closure, it can be (as in Ruby) be written after the closing parenthesis of the function call.
> A list comprehension is basically a cartesian product with a filter and map applied to it.
Ah yes, explain me more the concept I've been using for a dozen years, surely
I don't understand it. And with mix of terminology from as far topics as set
theory and functional programming, to lessen the confusion.
> What we have here is an array constructor, which takes one or more ranges as its arguments.
I would never have guessed the arguments thing.
> `x..<y` describes an open range (including x, excluding y).
I would never have guessed it's open range.
> you can also use positional arguments as in `{ ($0, $1) }` instead.
I would never have guessed, and I was writing in Perl with its magic variables
for more than a half of my professional career and most of my studies.
And that's the whole point: the syntax is so atrocious that it takes training
to understand it. I can accept the semantics to need training to understand
(as I did with Perl, Erlang, or now doing with Ada), but with this we haven't
hit that level yet.
So, your problem is that Swift's syntax in general isn't to your tastes, not the list comprehension proposal as such? Fair enough, but that's not what you were saying.
> Fair enough, but that's not what you were saying.
Then tell me, what was I saying?
>> I see very little connection, and I've seen list comprehensions in several different languages.
And then...
> So, your problem is [...] not the list comprehension proposal as such?
...you should get off your high horse. Your juggling with math terminology
earlier is not impressive. I know you wanted to sound smart, but you overdid
it and got smartass instead.
Let me rephrase then: what you seemed to be saying.
> ...you should get off your high horse. Your juggling with math terminology earlier is not impressive.
I'm not sure where you got that impression. I learned about Cartesian products in high school. Everything else I was talking about is at most first year computer science stuff.
I was simply trying to be precise, using the most basic terminology I could think of.
>Ah yes, explain me more the concept I've been using for a dozen years, surely I don't understand it.
Apparently you don't, as you appeared confused. Whether it was just the syntax of Swift that confused you, or something more general, the parent was not a medium to know.
In any case, the parent gave a general answer. If you already know some parts of the answer, you can skip them (others might not, and can find it useful) -- no need to be rude about it.
>I would never have guessed the arguments thing.
So? Tons of things a programming language does are not guessable if you don't know its semantics, and even less so if you also don't know its syntax. That doesn't even make them bad or difficult, just not already familiar.
>I would never have guessed it's open range.
I would. .. and ... are very common ways to describe ranges, and < is a logical thing to use to say it's open given its math meaning.
>I would never have guessed, and I was writing in Perl with its magic variables for more than a half of my professional career and most of my studies.
Well, I would have guessed all 3 of them. $0, $1 and the like are quite common, and at that place they couldn't be anything else but positional arguments.
>And that's the whole point: the syntax is so atrocious that it takes training to understand it.
Or it's so good that it takes training to understand it, as opposed to catering to the lowest common denominator of what people can immediately "guess".
That's precisely it. It just looks like a bunch of noise and then there's a result. People complain about list comprehensions in several languages where at least there is a structure to them and they don't look like crap. I can't imagine what the Swift community would say about code clarity and usage recommendations with regards to this proposition.
List comprehension is a bad idea, IMO. They were an improvement over not having anything like it, but python has improved over it (https://wiki.python.org/moin/Generators)
⇒ Generator expressions are the way to go. They would give you the sequence of elements without generating the (potentially enormous) data structure.
From there, methods to reify the items in a sequence would give you your list, array, or dictionary, where needed.
So, for Swift, I wouldn’t use
Array(1..<5, 3..<5) { ($0, $1) }
but the slightly longer
Array(for i in 1..<5, j in 3..<5 yield (i,j))
I’m not sure that is easy to fit in the existing parser, though. If it can be fit in, I would allow that code in ‘normal’ nested for loops, too.
This does not require a different syntax. You'd just construct a lazy list instead of an array.
Neither is an improvement over the other. Sometimes it's more important to have the results up front fast, sometimes generating them on demand is better.
It's a genuinely hard problem. There are proposals for Rust, but nothing actionable. Catching up with all the other cool things takes precedence. (side-note: Rust dodged the problem by using macros. As a C++ guy, I was a little uneasy with this, but they're _mostly_ hygenic)
Out of curiosity, what are the non-hygienic parts are of Rust macros? I'm pretty sure that non-procedural macros are hygienic, although I don't know a whole lot about the implementation of procedural macros.
Could you mention a genuine use case for variadic generics that's not “working around the stupidity of not reusing tuple types for so-called ‘n-ary’ procedures”?
it's an easy way to filter out odd/even numbers. `n % m` means "divide `n` by `m` and return the remainder". If you divide any even number by 2, the remainder is always 0, if you divide an odd number, it's always 1. Translate that to a boolean and you've got a nice odd/even filter.
I think you're being downvoted for being pedantic (and rude, in your edit), but I agree. This is a pretty good example of software engineers adopting mathematical terms they don't quite grasp in order to add an air of rigour to what they write. The statement is unhelpful for anyone that doesn't know what a Cartesian product is and irritatingly inaccurate for anyone who does.
I'm not sure of the original intent, but you could approach this as the Cartesian product of [1..5] * [1..10] * [1..10] which is then filtered such that the 2nd value is not smaller than the first, and the 3rd value is inclusively between the two
Exactly. Indeed, from what I recall from relational database theory, joins are usually treated as cartesian products (outer joins) which are then filtered by the join condition.
The Haskell list comprehension made sense to me the first time I saw it, but there is no way I'd know what the mess in the article was doing until someone explained to me.
Design has to come first. You can't just go with what's "Swifty" if that doesn't convey what's happening in a reasonable fashion.