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
How to Obtain a Swift Type from a String
Swift 3 Closure Overload Resolution
Dynamically Call a Function in Swift
Fetching Child Sum from Core Data
How to Make a Custom Geometryreader in Swiftui
How to Use Multiple Mtlrenderpipelinestates in One Mtlrendercommandencoder
Xcode 8 Swift 3 Pitch-Altering Sounds
Swift Enumerate Functions. How Does It Work Behind
Swift: Incrementing Label with Delay
Property with '= {Return}()' or '{Return}'
Get Current Url from Browser in MACos
How to Convert a Computed Value to a Literal for Enum Initialization
Change Notification from Observable Object as a Nested Object in Swiftui