12

In other languages such as Java, under the hood there is actually a difference between string obtained via string literal vs initializer. In Swift, are they equivalent under the hood?

e.g.

var string:String = ""
var string:String = String()

Refer to this SO post for info on differences between literal and object in Java.

Community
  • 1
  • 1
Boon
  • 40,656
  • 60
  • 209
  • 315

1 Answers1

13

The declarations are equivalent according to the Apple docs:

Initializing an Empty String

To create an empty String value as the starting point for building a longer string, either assign an empty string literal to a variable, or initialize a new String instance with initializer syntax:

var emptyString = ""               // empty string literal
var anotherEmptyString = String()  // initializer syntax
// these two strings are both empty, and are equivalent to each other

Reference: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html

If we look at the assembly, we will see that the two constructors use identical instructions.

string.swift:

let str = String()
let str2 = ""

Compiled assembly (swiftc -emit-assembly string.swift):

    .section    __TEXT,__text,regular,pure_instructions
    .macosx_version_min 14, 3
    .globl  _main
    .align  4, 0x90
_main:
    .cfi_startproc
    pushq   %rbp
Ltmp0:
    .cfi_def_cfa_offset 16
Ltmp1:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp2:
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    movq    _globalinit_33_1BDF70FFC18749BAB495A73B459ED2F0_token4@GOTPCREL(%rip), %rax
    movq    _globalinit_33_1BDF70FFC18749BAB495A73B459ED2F0_func4@GOTPCREL(%rip), %rcx
    xorl    %edx, %edx
    movl    %edi, -4(%rbp)
    movq    %rax, %rdi
    movq    %rsi, -16(%rbp)
    movq    %rcx, %rsi
    callq   _swift_once
    movq    _globalinit_33_1BDF70FFC18749BAB495A73B459ED2F0_token5@GOTPCREL(%rip), %rdi
    movq    _globalinit_33_1BDF70FFC18749BAB495A73B459ED2F0_func5@GOTPCREL(%rip), %rax
    xorl    %r8d, %r8d
    movl    %r8d, %edx
    movq    __TZvOSs7Process5_argcVSs5Int32@GOTPCREL(%rip), %rcx
    movl    -4(%rbp), %r8d
    movl    %r8d, (%rcx)
    movq    %rax, %rsi
    callq   _swift_once
    movq    __TZvOSs7Process11_unsafeArgvGVSs20UnsafeMutablePointerGS0_VSs4Int8__@GOTPCREL(%rip), %rax
    movq    -16(%rbp), %rcx
    movq    %rcx, (%rax)
    callq   __TFSSCfMSSFT_SS
    leaq    L___unnamed_1(%rip), %rdi
    xorl    %r8d, %r8d
    movl    %r8d, %esi
    movl    $1, %r8d
    movq    %rax, __Tv6string3strSS(%rip)
    movq    %rdx, __Tv6string3strSS+8(%rip)
    movq    %rcx, __Tv6string3strSS+16(%rip)
    movl    %r8d, %edx
    callq   __TFSSCfMSSFT21_builtinStringLiteralBp8byteSizeBw7isASCIIBi1__SS
    xorl    %r8d, %r8d
    movq    %rax, __Tv6string4str2SS(%rip)
    movq    %rdx, __Tv6string4str2SS+8(%rip)
    movq    %rcx, __Tv6string4str2SS+16(%rip)
    movl    %r8d, %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc

    .globl  __Tv6string3strSS
.zerofill __DATA,__common,__Tv6string3strSS,24,3
    .globl  __Tv6string4str2SS
.zerofill __DATA,__common,__Tv6string4str2SS,24,3
    .section    __TEXT,__cstring,cstring_literals
L___unnamed_1:
    .space  1

    .no_dead_strip  __Tv6string3strSS
    .no_dead_strip  __Tv6string4str2SS
    .linker_option "-lswiftCore"
    .section    __DATA,__objc_imageinfo,regular,no_dead_strip
L_OBJC_IMAGE_INFO:
    .long   0
    .long   512


.subsections_via_symbols

Notice that the declarations for str and str2 have identical instructions:

xorl    %r8d, %r8d
movl    %r8d, %esi
movl    $1, %r8d
movq    %rax, __Tv6string3strSS(%rip)
movq    %rdx, __Tv6string3strSS+8(%rip)
movq    %rcx, __Tv6string3strSS+16(%rip)
movl    %r8d, %edx

# ...

xorl    %r8d, %r8d
movq    %rax, __Tv6string4str2SS(%rip)
movq    %rdx, __Tv6string4str2SS+8(%rip)
movq    %rcx, __Tv6string4str2SS+16(%rip)
movl    %r8d, %eax

You can learn more about String literals by reviewing the Apple's documentation.

Community
  • 1
  • 1
JAL
  • 41,701
  • 23
  • 172
  • 300
  • My example code is from Apple doc as well. While it's equivalent from a usage standpoint, the doc doesn't say if it is equivalent behind the scene which is common since most language guides don't get to that level. – Boon Jul 03 '15 at 01:30
  • 1
    I am not at my build machine right now but if you compile a swift file with the two declarations using the `-emit-assembly` flag, it will show you that the declarations are identical. – JAL Jul 03 '15 at 01:39
  • @Boon It really is the same, there would be no way for those two expressions to be different, they evaluate to the same thing, there cannot even be an "under the hood" difference, because of how the standard library is made. If you can find a difference between those expressions then you made a mistake, because two expressions with an identical evaluation cannot be different – Kametrixom Jul 03 '15 at 01:39
  • @Kametrixom Your argument can be applied to Java as well but technically the two ways are different in Java under the hood. See my reference to the Java post in the question. – Boon Jul 03 '15 at 01:40
  • 1
    @Boon I know, that's why we're talking about Swift. In Swift (and NOT Java) those expressions evaluate to the SAME thing. Also JAL proved it just before by looking at the compiled assembly code – Kametrixom Jul 03 '15 at 01:43
  • @Kametrixom Thanks for pointing out JAL's point, missed that. – Boon Jul 03 '15 at 01:45
  • @JAL Thanks for the tip on emit-assembly. Can you include that in your answer and I will select it as answer? – Boon Jul 03 '15 at 01:45
  • 1
    @Boon Every single time you create a string like `""` or `String()` or `String("")` it doesn't matter how many times you create it, what matters is what's inside: There's nothing inside of all of those strings, so they are per definition the same – Kametrixom Jul 03 '15 at 01:46
  • 3
    Tangentially related... even in Objective-C, where `NSString` is a reference type, literal versus a constructor can frequently be the same under the hood. http://stackoverflow.com/a/31073079/2792531 – nhgrif Jul 03 '15 at 02:36
  • @Boon I have added the full compiled assembly to my answer, and highlighted the points where the declaration instructions overlap. – JAL Jul 03 '15 at 13:42
  • For the curious, here is the code for [`String.init()`](https://github.com/apple/swift/blob/master/stdlib/public/core/String.swift#L288), which calls [`_StringCore.init()`](https://github.com/apple/swift/blob/master/stdlib/public/core/StringCore.swift#L177), which sets the address of the string to [`emptyStringBase`](https://github.com/apple/swift/blob/master/stdlib/public/core/StringCore.swift#L738), which is a null pointer ([`_emptyStringStorage`](https://github.com/apple/swift/blob/master/stdlib/public/core/StringCore.swift#L736)) – Alexander Sep 09 '16 at 01:59