While a code change is in-progress, the developer may want to insert placeholders for certain values. For example, while they work on the the definition and implementation of a createWidget(...) function, they may have some code elsewhere like:
let someWidget = /* would use createWidget here, but it's not done */
In this case, if they want the project to still build while they flesh out the createWidget function, it would be handy to do this instead:
let someWidget = unimplemented()
Where unimplemented() could be written, say, as the following:
public func unimplemented<T>(context: String = "") -> T {
var errorMessage = "Reached unimplemented function"
if !context.isEmpty {
errorMessage += ": \(context)"
}
fatalError(errorMessage)
}
This is similar to the todo!() and unimplemented!() macros in Rust, and has been discussed for Swift before, such as here.
6 Likes
Personally, I don’t see any real use for it. In your example i normally start with the
func createWidget(name: String) → Widget {
Widget(name: ““)
}
or even
func createWidget(name: String) → Widget {
fatalError(“Not implemented“)
}
There you achieve the same result, but the compiler already has the function signature for doing it‘s stuff and you have to write it anyways sooner or later.
Also, how would the compiler know in your example what type widget is, without writing let someWidget: Widget = unimplemented. If its nil, it doesn’t help with further implementation.
4 Likes
maartene
(Maarten Engels)
3
I would rather see this solved at the tool level (I.e. in de the IDE) than as a language feature.
The tool could simply create the function as proposed by @flexlixrup .
2 Likes
vns
4
I find todo macro in Rust quite useful and just recently have had thoughts of it would be a good idea to bring similar solution to Swift in form of #todo or #todo(“message”). In overall, I’m for such addition.
2 Likes
maartene
(Maarten Engels)
5
I looked into the Rust solution a bit and I think I agree with you.
IIUC they have macro's that wrap panic which seems like their version of fatalError. Whereas we can of course always just use fatalError, perhaps using a macro named todo or unimplemented might signal more intend.
And might help IDE's collect these, just as some are able to spot // TODO: comments.
But I also still think that our IDEs could offer more support for refactoring/creation, something like what IntelliJ does for JAVA.
vns
6
That’s right, they have the same intentions.
I gave up on IDEs when it comes for Swift and use neovim whenever possible to avoid Xcode. And with Xcode still holding probably the biggest share of Swift developers, relying solely on tooling doesn’t promise a bright future; hopes for JetBrains-level IDE support probably only on Fleet.
1 Like
I think using this should result in a warning so that you remember to go back and implement it. We could implement this as a macro, in which case adding a warning would be easy.
7 Likes
crontab
(Hovik Melikyan)
8
That, and #UnimplementedView that could have some distinct visual representation (I usually do diagonal stripes) and a warning.
bbrk24
9
In the past, I’ve done this by making a function that wraps fatalError as demonstrated in the original post, and immediately marking it as deprecated. Deprecation warnings aren’t quite semantically correct but it is the easiest way to do this without custom macros.
1 Like
ktoso
(Konrad 'ktoso' Malawski 🐟🏴☠️)
10
When I came over to Swift many years ago I was missing this as well to be honest. In my case it was coming from Scala with its val example = ??? where ??? is just a method with a funny name with the same semantics 
I wonder if we were to consider such in swift we could make it immediately deprecated, so that usages of it trigger warnings immediately. Or rather, perhaps have it some other warning specific to this (in case one wanted to silence/allow it).
2 Likes
vns
11
I've played a bit with macros, and came up with freestanding and attached body versions:
func basic() -> Int {
#todo
}
func custom() -> Int {
#todo("I want to be free!")
}
@todo
func attachedBasic() -> Int
@todo("Run Forrest, run!")
func attachedCustom() -> Int
// this works as well
let x: Int = #todo
Producing output like this (probably can be improved even more, but good enough for example):
.../todo/Sources/todoClient/main.swift:4:5: warning: TODO: Implement me!
2 |
3 | func basic() -> Int {
4 | #todo
| `- warning: TODO: Implement me!
5 | }
6 |
...
.../todo/Sources/todoClient/main.swift:14:1: warning: TODO: Run Forrest, run
13 |
14 | @todo("Run Forrest, run")
15 | func attachedCustom() -> Int
| `- warning: TODO: Run Forrest, run
16 |
5 Likes
j-f1
(Jed Fox)
12
If you use context.diagnose in your macro instead of emitting #warning in the output, you can choose which node to apply the warning to.
4 Likes
vns
13
Didn’t think of it, thanks! Makes perfect sense
Could you share the implementation code please?