Proposal doesn't mention that, but it seems \n is used as line terminator for multi-line string literals on any platform. On Windows it can cause some problems. For instance, if some package has a test which reads some text file, then compares result to a multi-line string literal it will fail. This occurs because git by default converts all new lines in all text files in the working copy to platform-specific ones.
Is it by design or is it oversight?
Proposal: swift-evolution/0168-multi-line-string-literals.md at main · apple/swift-evolution · GitHub
1 Like
During the review, there was a pull request which included these details, but it wasn't merged by the Core Team. Normalization of line breaks was also mentioned in the decision notes, and in the language reference book.
Multiline string literals currently require a line break immediately after the opening quotation marks. We could support line break options in this position, e.g. """LF by default, """CRLF when required by a data format or platform.
2 Likes
Do you mean the compiler should check what kind of a new line follows """ then use it in a literal?
No, my suggestion is to have something visible, like a keyword or attribute.
Unfortunately that means some code (in my case tests) can't be cross-platform. My current solution is:
extension String {
var withPlatformNewLine: String {
#if os(Windows)
return replacingOccurrences(of: "\n", with: "\r\n")
#else
return self
#endif
}
}
If it's only for testing, you could split each string into an array of substrings (separated by any newline).
For example:
func XCTAssertEqualLines(
_ lhs: String,
_ rhs: String,
_ message: @autoclosure () -> String = "",
file: StaticString = #file,
line: UInt = #line
) {
let lhs: [Substring] = lhs.split(
omittingEmptySubsequences: false,
whereSeparator: \.isNewline
)
let rhs: [Substring] = rhs.split(
omittingEmptySubsequences: false,
whereSeparator: \.isNewline
)
XCTAssertEqual(lhs, rhs, message(), file: file, line: line)
}
In the future, we might be able to XCTAssertEqual(lhs.lines, rhs.lines) instead.
1 Like
This might be better for testing:
extension StringProtocol {
internal var lines: [SubSequence] {
split(omittingEmptySubsequences: false, whereSeparator: \.isNewline)
}
}
The StringProtocol extension makes .lines available on String and Substring.
2 Likes
SDGGiesbrecht
(Jeremy David Giesbrecht)
8
That sort of thing the correct solution. If Swift were to interpret source differently on different platforms, crossâcompilation would end up irreparably broken.
2 Likes
Much like this one. Does such change need to go through Swift Evolution?
masters3d
(Chéyo Jiménez)
11
This should be part of the standard library. Seems very useful.