Scala like placeholder for types


(Jon Hull) #1

Scala allows you to put a ??? placeholder for type names that temporarily allow you to work on the rest of a type without the compiler yelling at you unless you actually try to compile it. For example:

struct ??? { //I'll think of a name later
// Right now I want to focus here...
}

There would be no error about the missing type name until I actually try to compile this (at which point it tells me I need to provide a name). Similarly, I don't always want to figure out the exact return type of a function at the moment I create the function... sometimes I want to work out the algorithm first, and then come back to the type:

func foo() -> ??? { //I'll figure out the return type later
    //Right now I want to focus on the implementation
}

Again, the compiler wouldn't complain until I try to actually compile.

Finally, the thread on Opaque types has brought up the point that sometimes types are so unwieldy that it would be preferable for the compiler to infer the type instead of having to write it out. The function still has a concrete type, but that type is inferred from the return statements at compile time (and it is an error if they return different types):

func foo() -> ??? { //I am just going to let the compiler infer the type for me
    return "Foo"
}

It is easy to write String as the Type here, but as pointed out in the Opaque types thread, there are types that just obscure what the function is doing like so:

LazyMapSequence<LazyFilterSequence<LazyMapSequence<Elements, ElementOfResult?>>,ElementOfResult>

In these cases, when the compiler can infer the type, instead of causing an error during compile ??? would just be replaced by the compiler with the inferred type (just like the type of x in let x = bar() except we are explicitly asking for it). This would come at a cost of slightly increased compile times in some cases, but only where we have asked for it.

One advantage of this is that we could simplify the syntax for opaque types like so:

func foo()-> Int as Comparable //We see Int inside the function, but the outside world sees `opaque Comparable`

//We can infer the type
func foo()-> ??? as Comparable  //Int is inferred from our return type, the outside world still sees `opaque Comparable`

In this case we see that inferring the return type is just the composition of the ??? placeholder feature and a definition of Opaque types which always has an explicit spot for defining the internal type. (See that thread for why I think that is important).

Anyway, I wanted to see if people would find this placeholder behavior useful on it's own (separate from Opaque Types).


Opaque result types
(Jon Hull) #2

This would also apply to most names. For example, if I don't want to stop and think about what to call a function until after I have written it:

func ??? () -> Int {
    //I'll name it in a minute. Right now I want to work out the function itself...
}

Another option would be for the compiler to only generate a warning for things named ??? and just not compile those types/functions (since they can't actually be called). It would only be when you try to actually use it that it would stop compilation with an error...


(Xiaodi Wu) #3

Is there a reason you couldn’t name these, say, ___?


(Jon Hull) #4

No, I just used ??? because that is what other languages use, but we could use any symbol that doesn't conflict with the current grammar. The only thing with ___ is that it is hard to tell how many underscores there are...


(Xiaodi Wu) #5

I mean that ___ works as an identifier name without a new language feature. As to return type, I write -> Never and insert fatalError("not implemented") in the body. As Never becomes a true bottom type this will serve all use cases for a placeholder.


(Jon Hull) #6

Oh, well right now I just use something like XXXX and then I put something like Int as the return type (but I will try Never)... The issue is that I actually DO want the compiler to remind me if for some reason I forget to eventually name the thing and try to compile.

The other issue is that as soon as I start returning stuff in my implementation, the compiler yells at me about it, which is distracting. That may be fixed by your idea of using Never though.

The fact that you have hacked together your own way of doing this shows that you do have some need for it. In general, this is one of those features which is really nice to have in a language, but not essential. I had been thinking of asking for it for a while, but finally decided to bring it up, since it might also simplify the design of Opaque types at the same time.


(Konrad `Ktoso` Malawski) #7

Hi Jon,
I see where you might have seen the use of ??? in Scala examples however the ??? you are showing in the examples is not really the one present in Scala. Wanted to clarify this in case someone would be confused by this.

The Scala one is a simple method like this: def ??? : Nothing = throw new NotImplementedError https://github.com/scala/scala/blob/2.13.x/src/library/scala/Predef.scala#L340

For Swift this would be like the undefined done by Johannes Weiss over here: https://github.com/weissi/swift-undefined/blob/master/undefined.swift

there's no type things going on here really. It allows programmers to say val a: String = ??? which would be read as "I'll get a String a there, don't bother me about there it's coming from, assume it's there; but blow up at runtime with an NotImplementedError". For worrying after names later you can always use silly names like NameMeBetterPleaseTODOContainer etc I'd think :slight_smile:

So this allows for prototyping with proper names and types, and fill-in the implementation later on – so somewhat the opposite of what you are looking for.

Yes you could say class ??? in scala as well, but this is not special in any way really; it declared a class that is called ???, there are very few limitations about how you can name things in Scala (it desugars into a runtime name $qmark$qmark$qmark btw).

Rather it seems you are asking for return type inference for functions, which Swift seems to not have (and I can't really comment about the reasons there since I don't know –if I were to guess it's to avoid accidentally creating brittle APIs, relying on the inference too much which is fair); but that's a different feature to ask for I suppose :-) For reference: return type inference in Scala is handled by omitting the type ascription, same as you would for fields (def hello = "hello" being inferred as method returning String). It is indeed a pretty nice feature to have, but unrelated to the ??? :slight_smile:

Hope this helps,


(Jon Hull) #8

Thanks for the clarification.

Yes, I am meshing several ideas together here, and adapting them to Swift. Namely:
The ??? syntax
Some of the placeholder concepts
and some ideas from the Opaque Types Discussion

The main question is: Is this idea useful enough to be added as a feature by itself?

The answer might be no, and that is Ok. I wanted to see if it was something that people would find useful...


(Xiaodi Wu) #9

Thanks, that's useful clarification. Return type inference is indeed a whole nother kettle of fish.


(Greg Titus) #10

This works today with editor placeholders. If you type:

func <#name#>() -> Int {
}

Then this won't cause any errors while you are still in the middle of writing, and only error if you explicitly try to compile. Not only that, but in a playground, instead of an error, having a placeholder is only a warning, so you can run the playground with this still in it. And, of course, Xcode treats it specially for you as a token that's easy to click on and replace.


(Jon Hull) #11

@gregtitus That is awesome!