Anonymous structs is a feature I have thought about quite a bit and would really like to see. The syntax that I have had in mind is to make them quite similar to closures, but using double braces. A capture list would be used to assign properties and trailing syntax would also be supported. Your example would look like this:
printJson {{ [a = "Swift", b = 1337] in }}
Anonymous structs would be usable in any generic or existential type context. The anonymous struct would need to meet all requirements of that context. In the above example, since the context is Encodable
and the struct only stores encodable values the compiler synthesizes the conformance.
Stored properties that need to be mutable would have a var
modifier in the capture list.
When there is only a single requirement that cannot be met by stored properties there would be syntactic sugar allowing the body of the struct to be an implementation of that requirement. This syntactic sugar would support the same syntax as closures, supporting $ identifiers or a named (and optionally typed) list of arguments and an optional return type.
protocol P {
func foo(_ int: Int) -> Int
}
func takesP<T: P>(_ value: T) {}
// no need for stored properties
// the body implicitly provides an implementation of `foo`
// because the body is a single expression, return elision is allowed
takesP {{ $0 + 42 }}
takesP {{ int in int + 42 }}
takesP {{ int: Int -> Int in int + 42 }}
// explicit capture of context is required because it declares a stored property
let increment = 1
takesP {{ [increment] int: Int -> Int in int + increment }}
If the protocol has multiple requirements that must be fulfilled the body of the anonymous struct it becomes a more traditional type-level scope:
protocol P {
func foo(_ int: Int) -> Int
func bar(_ int: Int) -> Int
}
func takesP<T: P>(_ value: T) {}
takesP {{
func foo(_int: Int) -> Int { int + 42 }
func bar(_int: Int) -> Int { int - 44 }
}}
It's worth pointing out that this sugar is not only in contexts where trailing syntax can be used, that is just one example. Opaque result types and ad-hoc existential values are other good use cases for anonymous structs.