In Obj-C, I could define a macro
#define check_nil(x) if (!x) { return nil }
which can be used to test whether a function has returned nil (indicating an error), and if that's the case, the caller can simply return nil -- propagating the error up the stack. I am writing a parser, and this pattern happens very often. E.g.
- (id)caller {
...
id z = [self callee];
check_nil(z);
...
}
- (id)callee {
...
}
Unfortunately, after moving to swift, macros are gone. Function (with #autoclosure) are to replace them, but not in this case. Now my code is littered with identical if checks.
Any idea to replicate the same thing in Swift?
You are not going to be able to implement that pattern exactly.
Perhaps you could use a type that will turn future operations into no-ops if they ever return nil:
struct NonNil<T> {
var cantBeNil: T?
mutating func update(withClosure: () -> T?) {
if self.cantBeNil != nil {
self.cantBeNil = withClosure()
}
}
}
Then you can use this struct like so:
func myFunc() -> String? {
var nonNil = NonNil(cantBeNil: "")
nonNil.update {
// some action
return "new value"
}
nonNil.update {
// another action that ends up returning nil
return nil
}
// The rest of these don't end up calling the closure
nonNil.update {
println("not called")
return ""
}
nonNil.update {
println("not called")
return ""
}
return nonNil.cantBeNil
}
The idea being that if any operation returns nil, the rest of the code will fall through until the return statement, not executing any additional operations.
This will also visually separate all of the parts of the code that can cause the value to be set to nil
Related
So I'm making regexes for collections (all quantifiers are possessive). It looks like this (keep in mind the example is overly simplified for readability's sake):
val mayBeAPerson: Boolean = "totally not a person"
.toList()
.matches { // this: PatternScope
one { it.isUpperCase() } // execution of lambda could end after this method
moreThan(0) { it.isLetter() }
one { it == ' ' }
lessThan(2) { // this: PatternScope
one { it.isUpperCase() }
one { it == '.' }
one { it == ' ' }
}
one { it.isUpperCase() }
moreThan(0) { it.isLetter() }
}
As you can see, execution of lambda passed to matches could end after first one, as the predicate passed to it doesn't match first character in List. And it indeed does end. However, my solution is the opposite of elegant, as it uses throwing an exception in one and catching it in matches.
fun List<Char>.matches(build: PatternScope.() -> Unit) = try {
val scope = PatternScope(iterator())
scope.build() // may throw MatchFailed
!scope.iterator.hasNext()
} catch (_: MatchFailed) {
false
}
class PatternScope(private val iterator: Iterator<Char>) {
inline fun one(predicate: (element: Char) -> Boolean) {
if (!iterator.hasNext() || !predicate(iterator.next())) {
throw MatchFailed("match failed")
}
}
.
. etc
.
}
It totally works, but I can't help but wonder: is there a better way? I do know throwing exceptions like this is just a fancy GOTO, and I could wrap all the methods of PatternScope in ifs, like this:
class PatternScope(private val iterator: Iterator<Char>) {
private var matchFailed = false
inline fun one(predicate: (element: Char) -> Boolean) {
if (!matchFailed) {
if (!iterator.hasNext() || !predicate(iterator.next())) {
matchFailed = true
}
}
}
inline fun moreThan(n: Int, predicate: (element: Char) -> Boolean) {
if (!matchFailed) {
// logic
}
}
.
. etc
.
}
Is it more elegant though? Now I'm invoking all the functions in lambda passed to matches, and I like it even less to be honest.
My real question is: is there even better way to do it? Some magic solution to return from lambda I don't even have real access to? Some non-local returns, but from functions lambda hasn't even see yet?
Can I return from lambda by invoking some function inside its body?
Edit
Just to clarify, let's say we have a lambda:
val lambda: () -> Unit = {
someMethod() // this should return from lambda (in some cases)
someOtherMethod() // this shouldn't be invoked
}
How should the body of someMethod look like, so that someOtherMethod does not even execute when the lambda is invoked? Is there any other way but making someMethod throw an exception and wrapping lambda in try-catch block like this:
try {
lambda() // throws
} catch (_: SomeThrowableIdk) { }
I don't see a better way, but please prove me wrong.
I assume you're actually using #PublishedApi since you have a private iterator and public inline functions that access it.
Since Kotlin doesn't have checked exceptions, it is against Kotlin convention to throw Exceptions for things that are not actually errors in the program (bugs). Your first approach feels a little hacky for this reason. Since your API has public inline functions, there's no way to totally encapsulate the exceptions. You could switch to non-inline functions and storing the steps in a collection to be run internally, but this is surely more runtime overhead than the inline functions or your second approach with if statements.
Your second approach is more like a typical builder, so I don't see the problem with it. Since your functions are inline, it's not like your compiled code has a bunch of unnecessary function calls. Just if statements. You could however add a helper function to clean up your code at all the sub-functions, though I'm not sure if this can extend to the complexity of your actual class:
class PatternScope(#PublishedApi internal val iterator: Iterator<Char>) {
#PublishedApi internal var matchFailed = false
#PublishedApi internal inline fun nextRequire(require: () -> Boolean) {
matchFailed = matchFailed || !require()
}
inline fun one(predicate: (element: Char) -> Boolean) = nextRequire {
iterator.hasNext() && predicate(iterator.next())
}
}
There's no way to do what you described in your edit. Non-local returns work only with lambdas. To support something like what you describe, Kotlin would need syntax for a special kind of function that has the ability to return from the function that calls it. A function like this would have to have a new kind of signature that also declares the return type of the type of function that is permitted to call it. There simply is no such syntax or function type like that in Kotlin.
Essentially this is in the title. I have a value that could be null. If it is, I just want to exit with a message. If it's not null, then there's a whole slew of work I need to do with this value.
I've found similar, but not quite this exact situation. And it's the subtle difference that's driving me nuts. Here is my code in java:
if (value == null) {
print("error!");
return;
}
print(value);
doFunStuff(value);
etc(value);
All those methods using value require it to be non-null.
But I'm having a difficult time figuring this out in kotlin. With everything I try, the compiler still insists that value is still nullable and refuses to use it in the functions.
What is the kotlin way of doing this very common code flow?
If your methods truly have non-null parameters, the Kotlin compiler should be smart enough to do a smart cast to Object from Object?.
fun yourMethod(value: Object?) {
if (value == null) {
print("error!")
return
}
print(value) // Smart cast happens here
doFunStuff(value)
etc(value)
}
fun print(value: Object) {
// Implementation
}
fun doFunStuff(value: Object) {
// Implementation
}
fun etc(value: Object) {
// Implementation
}
But you can also force the conversion by using the !! operator (though in this case the compiler will tell you it's not necessary):
fun yourMethod(value: Object?) {
if (value == null) {
print("error!")
return
}
val nonNullValue = value!!
print(nonNullValue)
doFunStuff(nonNullValue)
etc(nonNullValue)
}
fun print(value: Object) {
// Implementation
}
fun doFunStuff(value: Object) {
// Implementation
}
fun etc(value: Object) {
// Implementation
}
If your value is a local variable or a function parameter, you won't have this problem, because the compiler will smart-cast it to not-null.
So, I'm assuming value in this case is a member property.
Option 1 is to copy it to a local variable to use in the function:
val value = value
if (value == null) {
print("error!")
return
}
print(value)
doFunStuff(value)
etc(value)
Option 2 is to use the let or also scope functions to do the same thing, but this might not be a good option here because so much code would become nested. This is more useful when you're only calling one or two functions with the object, in which case, you wouldn't even have to name it (just call it it).
value.let { value ->
if (value == null) {
print("error!")
return
}
print(value)
doFunStuff(value)
etc(value)
}
If your entire function works with this one property, you can avoid the nesting problem like this, if you don't mind it returning something besides Unit:
fun foo() = value.also { value ->
if (value == null) {
print("error!")
return
}
print(value)
doFunStuff(value)
etc(value)
}
Option 3 is to assert non-null every time you use it, but this is very ugly. This is only safe if you know the property is only ever accessed from the same thread this function is ever called on.
if (value == null) {
print("error!")
return
}
print(value!!)
doFunStuff(value!!)
etc(value!!)
Expanding on #Mehul's answer, this would only run the code in the let if the value was not null. If null, you could run the outside process and return from it.
value?.let { nonNullValue ->
print(nonNullValue);
doFunStuff(nonNullValue);
etc(nonNullValue);
}?: run { print("error!") ; return }
That said, since you are no longer needing the return to abort the function if null, you could simply do this and further clean it up replacing the lambda.
value?.let {
print(it);
doFunStuff(it);
etc(it);
}?: print("error!")
Well, have you already tried something like this and this is not what you expect?
value?.let { nonNullValue ->
print(nonNullValue);
doFunStuff(nonNullValue);
etc(nonNullValue);
}
basically the code inside let block will run only if the value isn't null.
How to return from an anonymous lambda in Kotlin?
Somehow the complier doesn't allow to return inside the lambda body. Since the lambda is anonym an return#... isn't possible here.
class Foo {
var function: (String) -> Unit = { _ -> }
init {
function = { text ->
if (text == "foo"){
// do side effects here
return
//'return' is not allowed here
//This function must return a value of type Foo
}
// do side other side effects
}
}
}
EDIT: update the example so it is clear that this question is about the return statement and not coding practices
Use Label:
class Foo {
var function: (String) -> Unit
init {
function = function# { text ->
if (text == "foo"){
return#function
}
print(text)
}
}
}
While it's possible to do, I'm not a fan of that sort of thing and prefer to restructure the flow when practical. In your example, it would be something like:
function = { text ->
if (text == "foo"){
// do side effects here
} else {
// do side other side effects
}
}
There are usually ways to keep the flow to a single return path, so you don't have to do strange things like have multiple return statements or use labels.
Objective-C:
#synchronized {
return;
}
NSLog(#"This line of code does not run.");
Objective-C's #synchronized is a language-level directive and does not introduce a new function scope.
Swift:
synchronized {
return
}
print("This line of code does run.")
func synchronized(lock: AnyObject, #noescape closure: () -> Void) {
objc_sync_enter(lock)
closure()
objc_sync_exit(lock)
}
Synchronized uses closures which do introduce a function scope.
Question:
Can I do the same in Swift? Does not introduce a new function scope.
Real Problem
public func stopRecording() {
synchronized(self) {
guard status == .Recording else { return }
status = .StoppingRecording
}
// Many somethings need to do, and I don`t want to write into the closure.
finishRecording()
......
......
......
}
Workaround:
if (synchronized(self) { return true }) {
return
}
print(#"This line of code does not run.")
func synchronized(lock: AnyObject, #noescape closure: () -> Bool) -> Bool {
objc_sync_enter(lock)
defer {
objc_sync_exit(lock)
}
return closure()
}
Someone has a elegant solution?
I just put together a solution that isn't too bad. We cannot introduce a custom language construct that doesn't introduce a new scope, therefore we need to use one of the existing ones. The if statement should work for that. I made a small class for that, which does but one thing: Lock the given object and check that the unlock method got called before it deallocates (along with some additions for debugging):
final class LockingManager {
let obj: AnyObject
let file: StaticString
let line: UInt
var locked = true
init(obj: AnyObject, file: StaticString, line: UInt) {
self.obj = obj
self.file = file
self.line = line
objc_sync_enter(obj)
}
func unlock() {
objc_sync_exit(obj)
locked = false
}
deinit {
precondition(!locked, "Object \(obj) not unlocked", file: file, line: line)
}
}
With a function like this:
func lock(obj: AnyObject, file: StaticString = #file, line: UInt = #line) -> (() -> Void)? {
return LockingManager(obj: obj, file: file, line: line).unlock
}
We can use it like this:
if let unlock = lock(obj: self) {
defer { unlock() }
// Do stuff
}
Since method never returns nil, you don't ever want an else part. Since the unlock method, which holds the only reference to the LockingManager, is only available within the if statement, after the statement the LockingManager gets deallocated. Upon deallocation, it checks whether the unlock method was called and if not, throws an error.
I understand that this isn't a super nice solution, but it does work in that it doesn't introduce a new scope (and additionally checks for correct usage).
Another solution would be to just use simple function calls and a do block:
do {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
// Do stuff
}
I personally prefer the second approach (with some better named functions), because it's much clearer what it does.
I want to rewrite this Objective-C method in Swift.
I'm trying to find the best way to do it.
- (UIDynamicItemBehavior*) itemBehaviourForView:(UIView*)view
{
for (UIDynamicItemBehavior* behaviour in _animator.behaviors)
{
if (behaviour.class == [UIDynamicItemBehavior class] && [behaviour.items firstObject] == view)
{
return behaviour;
}
}
return nil;
}
I wrote something like that:
func itemBehaviorForView(view :UIView)->UIDynamicItemBehavior
{
for dynamicItemBehavior in animator.behaviors
{
if dynamicItemBehavior is UIDynamicItemBehavior && dynamicItemBehavior.items.firstObject == view
{
return dynamicItemBehavior as UIDynamicItemBehavior
}
}
return nil
}
I see two problems:
dynamicItemBehavior.items.firstObject is not Array, so there is no firstObject method
I cannot return nil
What should I do about these?
If there is a possibility that the function will return nil then the function's return type needs to be an optional. In your case declare the function as:
func itemBehaviorForView (view:UIView) -> UIDynamicItemBehavior?
The documentation for UIDynamicItemBehavior declares items as an array with:
var items: [AnyObject]! { get }
and thus you would reference the first object using array subscript notation as:
dynamicItemBehavior.items[0]
Of course, the items might be empty. To handle that in idiomatic Swift use:
if dynamicItemBehavior is UIDynamicItemBehavior {
if let firstView = dynamicItemBehavior.items?[0] {
if firstView == view {
return dynamicItemBehavior as UIDynamicItemBehavior
}
}
}
where the use of if let <var> will bind <var> iff the result of ...items? is not nil.
More functional approach after conversion:
let r = (animator.behaviors.filter { $0 is UIDynamicItemBehavior } as [UIDynamicItemBehavior])
.filter({ $0.items?[0] === view })
return r.count > 0 ? r[0] : nil
And we can even shrink it to one line return if we bridgeToObjectiveC() the result to take advantage of firstObject property:
return (animator.behaviors.filter { $0 is UIDynamicItemBehavior } as [UIDynamicItemBehavior])
.filter({ $0.items?[0] === view }).bridgeToObjectiveC().firstObject as? UIDynamicItemBehavior
Remarks:
Objective-C == to compare references in Swift achieved with ===.
I know that initial Objective-C algorithm was eager and returned as soon as match found. Show the expressiveness of functional approach.
I think Keenle was on the right track with using a functional style. But this is not a job for filter, this is a job for find. It will stop early on the first match it encounters. Unfortunately Swift does not currently implement find for us (unlike filter), but we can add it with extensions!
Unlike the other answers here, I don't know the type of animator or behaviors. I'm going to assume that behaviors is an NSArray, if that assumption is incorrect, please let me know.
extension NSArray {
func find(predicate: (AnyObject) -> Bool) -> AnyObject? {
for element: AnyObject in self {
if predicate(element) {
return element
}
}
return nil
}
}
Now we just have to update your function to use this!
func itemBehaviorForView(view: UIView) -> UIDynamicItemBehavior?
{
func predicate(object: AnyObject) -> Bool {
if let dynamicItemBehavior = object as? UIDynamicItemBehavior {
return view === dynamicItemBehavior.items?[0]
}
return false
}
return animator.behaviors.find(predicate) as? UIDynamicItemBehavior
}
I will admit, the casting on the final return statement is a little bit ugly. If animator.behaviors was know to only contains objects of the acceptable return type we could avoid this, but you're likely stuck with this because of the obj-c code.