What follows is an attempt to determine
-
whether the function name mangling machine (FNMM) has something against single unnamed element tuple types
only when they appear in vanilla parameters or whether it just objects to them on principle wherever they appear
-
whether it has any idiosyncracies with respect to any of the other possible tuple types.
There are effectively four kinds of tuple.
-
the empty tuple
-
unnamed element tuples, i.e., tuples where all the elements are unnamed
-
named element tuples, i.e., tuples where all the elements are named
-
mixed element tuples, i.e., tuples which are a mixture of named and unnamed elements
Unnamed and named tuples can further be divided into single and multiple element cases.
Tuple types can appear in the declarations of return types and of parameter types and as components of other type declarations.
1.0 Return Types
1.1 Void
We already know that the FNMM encodes the empty tuple type as
T_
whenever it is used as a return type.
1.2 Unnamed Element Tuples
1.2.1 Single Element
Compiling
func cod() -> (Int)
{
return (0)
}
gives us the symbol
__TF4xper3codFT_Si
so the FNMM also flattens a single element tuple type when it is used as a return type.
This means that there is a collision between the mangled names of functions which return
T
and those which return
(T)
and have identical parameters.
In practice it turns out that the compiler considers them to be the same function when it can see both of them at the same time
$ swiftc -module-name xper -emit-library functions03.swift
functions03.swift:8:6: error: invalid redeclaration of 'cod()'
func cod() -> (Int)
^
functions03.swift:3:6: note: 'cod()' previously declared here
func cod() -> Int
^
Then there are optionals.
Compiling
func cod() -> (Int)?
{
return (0)
}
gives us the symbol
__TF4xper3codFT_GSqSi_
The FNMM has flattened the tuple type again.
Compiling
func cod() -> (Int)!
{
return (0)
}
gives us the symbol
__TF4xper3codFT_GSQSi_
At least the FNMM is consistent, but is it recursive ?
Compiling
func cod() -> (((Int)))
{
return (((0)))
}
gives us the symbol
__TF4xper3codFT_Si
so the FNMM is indeed recursive.
Compiling
func cod() -> [(Int)]
{
return []
}
gives us the symbol
__TF4xper3codFT_GSaSi_
so the FNMM is not easily fooled either.
1.2.2 Multi Element
Compiling
func cod() -> (Int, String, Int)
{
return (1, "", 5)
}
gives us the symbol
__TF4xper3codFT_TSiSSSi_
The FNMM does not treat a multiple unnamed element tuple type specially when it is used as a return type.
1.3 Named Tuples
1.4 Single Element
Compiling
func cod() -> (i: Int)
{
return (i: 0)
}
doesnt.
Instead this happens
$ swiftc -module-name xper -emit-library functions03.swift
functions03.swift:40:16: error: cannot create a single-element tuple with an element label
func cod() -> (i: Int)
^~~
so the FNMM never gets the chance to encode the return type.
The compiler error message is a tad misleading.
You CAN create a single named element tuple, for example, this will compile
func cod() -> (Int)
{
let t = (i: 0)
return t
}
you just cannot explictly specify its type, so this version will not compile
func cod() -> (Int)
{
let t : (i: Int) = (i: 0)
return t
}
and the reason for that is probably because that isn’t its type.
Note the return type of the function and the fact that this compiles
func cod() -> (Int)
{
let t : (Int) = (i: 0)
return t
}
1.4 Multi Element
Compiling
func cod() -> (i: Int, j: Int)
{
return (i: 0, j: 0)
}
gives us the symbol
__TF4xper3codFT_T1iSi1jSi_
The FNMM does not treat a multiple named element tuple type specially when it is used as a return type.
Of course, compiling
func cod() -> (i: (Int), j: (Int))
{
return (i: 0, j: 0)
}
also gives us the symbol
__TF4xper3codFT_T1iSi1jSi_
Luckily this is not a problem as the compiler, as in the case above, considers them to be one and the same function.
$ swiftc -module-name xper -emit-library somefuncs.swift
somefuncs.swift:7:6: error: invalid redeclaration of 'cod()'
func cod() -> (i: (Int), j: (Int))
^
somefuncs.swift:1:6: note: 'cod()' previously declared here
func cod() -> (i: Int, j: Int)
^
1.5 Mixed Element Tuples
Compiling
func cod() -> (s String, String)
{
return (s: "", "")
}
gives us the symbol
__TF4xper3codFT_T1sSSSS_
The FNMM does not treat a mixed element tuple type specially when it is used as a return type.
2.0 Parameters
2.1 Vanilla
2.1.1 Void
Compiling
func cod(t:())
{
}
gives us the symbol
__TF4xper3codFT_T_
A function that takes a Void
argument is the same as function that takes no arguments at all.
Digression
Of course, a function that takes more than one Void
argument is not the same as function that takes no arguments at all.
Compiling
func cod(v0:(), v1:(), v2:())
{
}
gives us the symbol
__TF4xper3codFTT_T_T__T_
Discuss.
End of digression
2.1.2 Unnamed Element Tuples
2.1.2.1 Single Element
We already know the answer to this one.
The FNMM flattens a single unnamed element tuple type when it appears as the type of a vanilla parameter.
2.1.2.2 Multi Element
Compiling
func cod(e t:(Int, Int))
{
}
gives us the symbol
__TF4xper3codFTSiSi_T_
The FNMM does not treat a multiple unnamed element tuple type specially when it is used as the type of a vanilla parameter.
2.1.3 Named Tuples
2.1.3.1 Single Element
As in the return type case above, not supported by the compiler.
2.1.3.2 Multi Element
Compiling
func cod(e t:(x:Int, y:Int))
{
}
gives us the symbol
__TF4xper3codFT1xSi1ySi_T_
The FNMM does not treat a multiple named element tuple type specially when it is used as the type of a vanilla parameter.
2.1.4 Mixed Element Tuples
Compiling
func cod(t:(x:Int, String, y:Int))
{
}
gives us the symbol
__TF4xper3codFT1xSiSS1ySi_T_
The FNMM does not treat a mixed element tuple type specially when it is used as the type of a vanilla parameter.
2.2 External Names
2.2.1 Void
Compiling
func cod(e t:())
{
}
gives us the symbol
__TF4xper3codFT1eT__T_
How do you call it ?
Like this, obviously
cod(t:())
2.2.2 Unnamed Element Tuples
2.2.2.1 Single Element
Compiling
func cod(e t:(Int))
{
}
gives us the symbol
__TF4xper3codFT1eSi_T_
The FNMM has flattened the single unnamed element tuple type as usual.
2.2.2.2 Multi Element
Compiling
func cod(e t:(Int, Int))
{
}
gives us the symbol
__TF4xper3codFT1eTSiSi__T_
The FNMM does not treat a multiple unnamed element tuple types specially when it is used as the type of a vanilla parameter with an external name.
2.2.3 Named Element Tuples
2.2.3.1 Single Element
Not supported by the compiler.
2.2.3.2 Multi Element
Compiling
func cod(e t:(i: Int, j:Int))
{
}
gives us the symbol
__TF4xper3codFT1eT1iSi1jSi__T_
The FNMM does not treat a multiple named element tuple type specially when it is used as the type of a vanilla parameter with an external name.
2.2.4 Mixed Element Tuples
Compiling
func cod(e t:(x:Int, String, y:Int))
{
}
gives us the symbol
__TF4xper3codFT1eT1xSiSS1ySi__T_
The FNMM does not treat a mixed element tuple type specially when it is used as the type of a vanilla parameter with an external name.
2.3 inout
2.3.1 Void
Compiling
func cod(inout t:())
{
}
gives us the symbol
__TF4xper3codFRT_T_
Yes you can call it.
You need a mutable empty tuple of course.
$ swift
Welcome to Swift! Type :help for assistance.
1> func cod(inout t:()) { println(t) }
2> func dab()
3. {
4. var empty : () = ()
5.
6. cod(&empty)
7. }
8> dab()
()
9>
You can have an external name as well if you want.
Compiling
func cod(inout e t:())
{
}
gives us the symbol
__TF4xper3codFT1eRT__T_
2.3.2 Unnamed Element Tuples
2.3.2.1 Single Element
Compiling
func cod(inout t:(Int))
{
}
gives us the symbol
__TF4xper3codFRSiT_
and compiling
func cod(inout e t:(Int))
{
}
gives us the symbol
__TF4xper3codFT1eRSi_T_
In both cases the FNMM has flattened the single unnamed element tuple type as usual.
2.3.2.2 Multi Element
Compiling
func cod(inout t:(Int, Int))
{
}
gives us the symbol
__TF4xper3codFRTSiSi_T_
and compiling
func cod(inout e t:(Int, Int))
{
}
gives us the symbol
__TF4xper3codFT1eRTSiSi__T_
The FNMM does not treat a multiple named element tuple type specially when it is used as the type of an inout parameter with or without an external parameter.
2.3.3 Named Element Tuples
2.3.3.1 Single Element
Not supported by the compiler.
2.3.3.2 Multi Element
Compiling
func cod(inout t:(x:Int, y:Int))
{
}
gives us the symbol
__TF4xper3codFRT1xSi1ySi_T_
and compiling
func cod(inoute t:(x:Int, y:Int))
{
}
gives us the symbol
__TF4xper3codFT1eRT1xSi1ySi__T_
The FNMM does not treat a multiple named element tuple type specially when it is used as the type of an inout parameter with or without an external name.
2.3.4 Mixed Element Tuples
Compiling
func cod(inout t:(x:Int, String, y:Int))
{
}
gives us the symbol
__TF4xper3codFRT1xSiSS1ySi_T_
and compiling
func cod(inout e t:(x:Int, String, y:Int))
{
}
gives us the symbol
__TF4xper3codFT1eRT1xSiSS1ySi__T_
The FNMM does not treat a mixed element tuple type specially when it is used as the type of an inout parameter with or without an external name.
2.4 varadic
2.4.1 Void
Compiling
func cod(t:()...)
{
}
gives us the symbol
__TF4xper3codFtGSaT___T_
and you can call it too.
You end up with an array of empty tuples.
Compiling
func cod(voids t:()...)
{
}
gives us the symbol
__TF4xper3codFt5voidsGSaT___T_
Needless to say you can call that one as well.
2.4.2 Unnamed Element Tuples
2.4.2.1 Single Element
Compiling
func cod(t:(Int)...)
{
}
gives us the symbol
__TF4xper3codFtGSaSi__T_
and compiling
func cod(ints t:(Int)...)
{
}
gives us the symbol
__TF4xper3codFt4intsGSaSi__T_
In both cases the FNMM has flattened the single element tuple type as usual.
2.4.2.2 Multi Element
Compiling
func cod(t:(Int, Int)...)
{
}
gives us the symbol
__TF4xper3codFtGSaTSiSi___T_
and compiling
func cod(e t:(Int, Int)...)
{
}
gives us the symbol
__TF4xper3codFt1eGSaTSiSi___T_
The FNMM does not treat a multiple unnamed element tuple type specially when it is used as the type of a varadic parameter with or without an external name.
2.4.3 Named Element Tuples
2.4.3.1 Single Element
Not supported by the compiler.
2.4.3.2 Multi Element
Compiling
func cod(t:(i:Int, j:Int)...)
{
}
gives us the symbol
__TF4xper3codFtGSaT1iSi1jSi___T_
and compiling
func cod(e t:(i:Int, j:Int)...)
{
}
gives us the symbol
__TF4xper3codFt1eGSaT1iSi1jSi___T_
The FNMM does not treat a multiple named element tuple type specially when it is used as the type of a varadic parameter with or without an external name.
2.4.4 Mixed Element Tuples
Compiling
func cod(t:(x:Int, String, y:Int)...)
{
}
gives us the symbol
__TF4xper3codFtGSaT1xSiSS1ySi___T_
and compiling
func cod(e t:(x:Int, String, y:Int)...)
{
}
gives us the symbol
__TF4xper3codFt1eGSaT1xSiSS1xSi___T_
The FNMM does not treat a mixed element tuple type specially when it is used as the type of a varadic parameter with or without an external name.
3.0 Conclusion
The FNMM simply cannot abide single unnamed element tuple types. Either that or they don’t exist.
Postscript
While ploughing through that lot it occurred to me that the FNMM’s dislike of single unnamed element tuple types is at the bottom of the way in which it encodes a function’s parameters.
Unfortunately the explanation is too long to fit into the margin of this post.
Copyright (c) 2014 By Simon Lewis. All Rights Reserved.
Unauthorized use and/or duplication of this material without express and written permission from this blog’s author and owner Simon Lewis is strictly prohibited.
Excerpts and links may be used, provided that full and clear credit is given to Simon Lewis and justanapplication.wordpress.com with appropriate and specific direction to the original content.