Just An Application

October 27, 2014

So Swift Then: More Fun With Mangled Names

What follows is an attempt to determine

  1. 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

  2. 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.

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: