How to Handle a Fail to Init

Proper way to handle a fail to init

Use a failable initializer. Such an initializer looks very similar to a regular designated initializer, but has a '?' character right after init and is allowed to return nil. A failable initializer creates an optional value.

struct Animal {
let species: String
init?(species: String) {
if species.isEmpty { return nil }
self.species = species
}
}

See Apple's documentation on failable initializers for more detail.

How should I handle a failure in an init: method in Objective-C?

Yes, you should release yourself and then return nil.

[self release];
self = nil;

See Issues with Initializers in the Concepts in Objective-C Programming guide.

Ruby: How to handle a Failed or Invalid Initialization

I'd try to convert the argument and raise a TypeError if no conversion was possible:

Raised when encountering an object that is not of the expected type.

[1, 2, 3].first("two")

raises the exception:

TypeError: can't convert String into Integer

The Ruby core and standard libraries do it so there's no reason you can't do it too. The Ruby core will raise exceptions when you do something you're not supposed to (calling an unsupported method, calling a method with the wrong number of arguments, ...) so throwing a TypeError would make sense. And, if TypeError isn't quite appropriate, there's always ArgumentError.

In your specific case, try to convert the argument to an NSURL by calling to_s and then instantiating an NSURL using that string if they don't give you an NSURL. I don't know my way around MacRuby or the corresponding Mac APIs so I'm sort of guessing on the sensible behavior in this specific case but I think the "convert or raise an exception" idea is sound and sensible.

Of course, you should document the behavior you're going to use in your API documentation too.

Handle exception in __init__

It is perfectly fine to raise an exception in __init__. You would then wrap the object initiation/creation call with try/except and react to the exception.

One potential odd result though is that __del__ is run anyway:

class Demo(object):
def __init__(self, value):
self.value=value
if value==2:
raise ValueError
def __del__(self):
print '__del__', self.value

d=Demo(1) # successfully create an object here
d=22 # new int object labeled 'd'; old 'd' goes out of scope
# '__del__ 1' is printed once a new name is put on old 'd'
# since the object is deleted with no references

Now try with the value 2 that we are testing for:

Demo(2)
Traceback (most recent call last):
File "Untitled 3.py", line 11, in <module>
Demo(2)
File "Untitled 3.py", line 5, in __init__
raise ValueError
ValueError
__del__ 2 # But note that `__del__` is still run.

The creation of the object with value 2 raises a ValueError exception and show that __del__ is still run to clean up the object.

Keep in mind that if you raise an exception during __init__ your object will not get a name. (It will, however, be created and destroyed. Since __del__ is paired with __new__ it still gets called)

ie, just like this does not create x:

>>> x=1/0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

Potential sneakier:

>>> x='Old X'
>>> x=1/0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> x
'Old X'

Same thing if you catch an exception of __init__:

try:
o=Demo(2)
except ValueError:
print o # name error -- 'o' never gets bound to the object...
# Worst still -- 'o' is its OLD value!

So don't try to refer to the incomplete object o -- it's gone out of scope by the time you get to except. And the name o is either nothing (i.e., NameError if you try to use it) or its old value.

So wrapping up (thanks to Steve Jessop for the User Defined Exception idea), you can wrap the creation of the object and catch the exception. Just figure out how to react appropriately to the OS error you are looking at.

So:

class ForbiddenTwoException(Exception): 
pass

class Demo(object):
def __init__(self, value):
self.value=value
print 'trying to create with val:', value
if value==2:
raise ForbiddenTwoException
def __del__(self):
print '__del__', self.value

try:
o=Demo(2)
except ForbiddenTwoException:
print 'Doh! Cant create Demo with a "2"! Forbidden!!!'
# with your example - react to being unusable to create a directory...

Prints:

trying to create with val: 2
Doh! Cant create Demo with a "2"! Forbidden!!!
__del__ 2

How to handle initialization error occurred in constructor with no return allowed in constructor

You should throw an exception and use a try-catch around the call to the constructor.

Python __init__ return failure to create

You could raise an exception when either assertio fail, or -, if you really don't want or can't work with exceptions, you can write the __new__ method in your classes -
in Python, __init__ is technically an "initializer" method - and it should fill in he attributes and acquire some of the resources and others your object will need during its life cycle - However, Python does define a real constructor, the __new__ method, which is called prior to __init__- and unlike this, __new__ actually does return a value: the newly created (uninitialized) instance itself.

So you can place your checks inside __new__ and and simply return None is something fails - otherwise, return the result of the call to the superclass __new__ method (one can't do the actual memory allocation for the object in pure Python, so ultimately you have to call a constructor written in native code in a superclass - usually this is object.__new__ in the base of your class hierarchy.

NB: In Python 2, you must have object as the base class for your hierarchy - otherwise not only __new__ is not called, as a whole lot of features added later to Python objects will just not work. In short, class MyClass(object): , never class MyClass: - unless you are on Python3.

How to handle initializer error in multiprocessing.Pool?

After navigating through the implementation of multiprocessing using PyCharm, I'm convinced that there is no better solution, because Pool started a thread to _maintain_pool() by _repopulate_pool() if any worker process exists--either accidentally or failed to initialize.

Check this out: Lib/multiprocessing/pool.py line 244

Why not throw an exception if [super init] returns nil?

One reason, why you should do, what JustSid is saying:

In object-orientated design you should always code, as if you maybe will hand your class over to another project by another developer. So you can't assume, that a failure in initialization in his project may be as bad as it is probably in yours. Maybe this developer is you in 5 years. Imagine your hassle to fix your 200 classes, you want to reuse.



Related Topics



Leave a reply



Submit