NSMutableData's init?(length length: Int) initializer


(soyer) #1

Hello Guys, Girls,

Do you know why is the init?(length length: Int) NSMutableData's initializer failable?
The memory allocation can fail, but I think Swift doesn't handle that cases. (it is not a real issue in a modern OS)
The code on github calls a non failable initializer.
https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/NSData.swift#L904

public convenience init?(length: Int) {
  let memory = malloc(length)
  self.init(bytes: memory, length: length, copy: false) { buffer, amount in
    free(buffer)
  }
}

Thanks
s


(Jens Alfke) #2

Do you know why is the init?(length length: Int) NSMutableData's initializer failable?

Because the Objective-C declaration in <Foundation/NSData.h> declares the return type as ‘nullable’:

- (nullable instancetype)initWithLength:(NSUInteger)length;

The memory allocation can fail, but I think Swift doesn't handle that cases. (it is not a real issue in a modern OS)

Not on a modern 64-bit desktop OS, but it can be an issue on some other platforms. In a 32-bit process (still supported on iOS and Mac OS) malloc can fail if the process's address space is fragmented enough that there are no free blocks large enough for the allocation. On an OS without a VM pager, like many embedded systems, malloc can fail if physical RAM is exhausted.

(I’m actually not sure if this is the reason why that initializer is failable. It’s possible this is a mistake, or Apple’s frameworks team had some other architectural reason for allowing it to fail. Historically, the design pattern for initializers in Objective-C always allows them to return nil.)

The code on github calls a non failable initializer.

That’s for the native-Swift Foundation framework coming in Swift 3. I’d guess they’ve adopted the same method signature as in Apple’s Foundation, for compatibility.

—Jens

···

On Apr 14, 2016, at 10:45 AM, soyer via swift-users <swift-users@swift.org> wrote:


(Jacob Bandes-Storch) #3

It's easy to test this in a playground on OS X:

    NSMutableData(length: 1000000000000000) // returns nil

It makes sense that the swift-corelibs-foundation version of NSMutableData
should work the same way.
Jacob

···

On Thu, Apr 14, 2016 at 11:56 AM, Jens Alfke via swift-users < swift-users@swift.org> wrote:

On Apr 14, 2016, at 10:45 AM, soyer via swift-users <swift-users@swift.org> > wrote:

Do you know why is the init?(length length: Int) NSMutableData's
initializer failable?

Because the Objective-C declaration in <Foundation/NSData.h> declares the
return type as ‘nullable’:

- (nullable instancetype)initWithLength:(NSUInteger)length;

The memory allocation can fail, but I think Swift doesn't handle that
cases. (it is not a real issue in a modern OS)

Not on a modern 64-bit desktop OS, but it can be an issue on some other
platforms. In a 32-bit process (still supported on iOS and Mac OS) malloc
can fail if the process's address space is fragmented enough that there are
no free blocks large enough for the allocation. On an OS without a VM
pager, like many embedded systems, malloc can fail if physical RAM is
exhausted.

(I’m actually not sure if this is the reason why that initializer is
failable. It’s possible this is a mistake, or Apple’s frameworks team had
some other architectural reason for allowing it to fail. Historically, the
design pattern for initializers in Objective-C always allows them to return
nil.)

The code on github calls a non failable initializer.

That’s for the native-Swift Foundation framework coming in Swift 3. I’d
guess they’ve adopted the same method signature as in Apple’s Foundation,
for compatibility.

—Jens

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Chris Lattner) #4

Swift’s policy on memory allocation failure is that fixed-size object allocation is considered to be a runtime failure if it cannot be handled. OTOH, APIs that can take a variable and arbitrarily large amount to allocate should be failable. NSData falls into the later category.

-Chris

···

On Apr 14, 2016, at 10:45 AM, soyer via swift-users <swift-users@swift.org> wrote:

Hello Guys, Girls,

Do you know why is the init?(length length: Int) NSMutableData's initializer failable?
The memory allocation can fail, but I think Swift doesn't handle that cases. (it is not a real issue in a modern OS)
The code on github calls a non failable initializer.
https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/NSData.swift#L904


(Dmitri Gribenko) #5

Does this principle apply to Array(repeating:count:)?
Array.append(contentsOf:)?

Dmitri

···

On Thu, Apr 14, 2016 at 11:16 PM, Chris Lattner via swift-users <swift-users@swift.org> wrote:

On Apr 14, 2016, at 10:45 AM, soyer via swift-users <swift-users@swift.org> wrote:

Hello Guys, Girls,

Do you know why is the init?(length length: Int) NSMutableData's initializer failable?
The memory allocation can fail, but I think Swift doesn't handle that cases. (it is not a real issue in a modern OS)
The code on github calls a non failable initializer.
https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/NSData.swift#L904

Swift’s policy on memory allocation failure is that fixed-size object allocation is considered to be a runtime failure if it cannot be handled. OTOH, APIs that can take a variable and arbitrarily large amount to allocate should be failable. NSData falls into the later category.

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Chris Lattner) #6

As you know well enough, “no”. :-)

-Chris

···

On Apr 14, 2016, at 11:22 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:

On Thu, Apr 14, 2016 at 11:16 PM, Chris Lattner via swift-users > <swift-users@swift.org> wrote:

On Apr 14, 2016, at 10:45 AM, soyer via swift-users <swift-users@swift.org> wrote:

Hello Guys, Girls,

Do you know why is the init?(length length: Int) NSMutableData's initializer failable?
The memory allocation can fail, but I think Swift doesn't handle that cases. (it is not a real issue in a modern OS)
The code on github calls a non failable initializer.
https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/NSData.swift#L904

Swift’s policy on memory allocation failure is that fixed-size object allocation is considered to be a runtime failure if it cannot be handled. OTOH, APIs that can take a variable and arbitrarily large amount to allocate should be failable. NSData falls into the later category.

Does this principle apply to Array(repeating:count:)?
Array.append(contentsOf:)?


(Dmitri Gribenko) #7

Why? These APIs also "take a variable and arbitrarily large amount to
allocate".

Dmitri

···

On Fri, Apr 15, 2016 at 10:34 AM, Chris Lattner <clattner@apple.com> wrote:

On Apr 14, 2016, at 11:22 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:

On Thu, Apr 14, 2016 at 11:16 PM, Chris Lattner via swift-users >> <swift-users@swift.org> wrote:

On Apr 14, 2016, at 10:45 AM, soyer via swift-users <swift-users@swift.org> wrote:

Hello Guys, Girls,

Do you know why is the init?(length length: Int) NSMutableData's initializer failable?
The memory allocation can fail, but I think Swift doesn't handle that cases. (it is not a real issue in a modern OS)
The code on github calls a non failable initializer.
https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/NSData.swift#L904

Swift’s policy on memory allocation failure is that fixed-size object allocation is considered to be a runtime failure if it cannot be handled. OTOH, APIs that can take a variable and arbitrarily large amount to allocate should be failable. NSData falls into the later category.

Does this principle apply to Array(repeating:count:)?
Array.append(contentsOf:)?

As you know well enough, “no”. :slight_smile:

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Jordan Rose) #8

I might split the difference here: trying to append a very large sequence would be a programmer error, but trying to allocate a very large array might not be.

UnsafeMutablePointer.init(allocatingCapacity:) is also currently non-failable.

Jordan

···

On Apr 15, 2016, at 10:36, Dmitri Gribenko via swift-users <swift-users@swift.org> wrote:

On Fri, Apr 15, 2016 at 10:34 AM, Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

On Apr 14, 2016, at 11:22 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:

On Thu, Apr 14, 2016 at 11:16 PM, Chris Lattner via swift-users >>> <swift-users@swift.org> wrote:

On Apr 14, 2016, at 10:45 AM, soyer via swift-users <swift-users@swift.org> wrote:

Hello Guys, Girls,

Do you know why is the init?(length length: Int) NSMutableData's initializer failable?
The memory allocation can fail, but I think Swift doesn't handle that cases. (it is not a real issue in a modern OS)
The code on github calls a non failable initializer.
https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/NSData.swift#L904

Swift’s policy on memory allocation failure is that fixed-size object allocation is considered to be a runtime failure if it cannot be handled. OTOH, APIs that can take a variable and arbitrarily large amount to allocate should be failable. NSData falls into the later category.

Does this principle apply to Array(repeating:count:)?
Array.append(contentsOf:)?

As you know well enough, “no”. :slight_smile:

Why? These APIs also "take a variable and arbitrarily large amount to
allocate".