YapDatabaseViewTransaction, YapDatabaseViewConnection in 2.7.4
Now that YapDatabaseTransaction's ext method returns a nullable __kindof YapDatabaseExtensionTransaction * type instead of just id like previously, Swift maps it as YapDatabaseExtensionTransaction? so downcasting is necessary to be able to call YapDatabaseViewTransaction's objectAtIndexPath method for instance.
I applaud the improvements towards strong type safety, but what would be the cleanest way do work with view-related transactions and connections? Do I simply guard, if let the conversions or force them? Or is there another way I'm not aware of?
I'm curious what the community thinks about this.
Is id the proper return type in this instance? Or is forcing a cast better?
@sbooth @jj0b @chrisballinger
@robbiehanson though it is a bit verbose, I think I'm ok with force casting. I'm curious what others think.
@onfoot this is what I've been doing:
uiDatabaseConnection.readWithBlock { (transaction) -> Void in
someObject = (transaction.ext(kSomeDatabaseView)! as! YapDatabaseViewTransaction).objectAtIndexPath(indexPath, withMappings:self.mappings!) as! SomeObject
}
Currently I'm doing the same thing as @jj0b because it seems to me that the programmer should always know (in my limited experience with YapDB) what type of transaction will be returned from ext.
One idea I've been toying with is that each extension could implement a category on YapDatabaseReadTransaction to return the proper type:
@interface YapDatabaseReadTransaction (SecondaryIndex)
- (nullable YapDatabaseSecondaryIndexTransaction *) secondaryIndexTransaction:(NSString *)extensionName;
@end
and
@implementation YapDatabaseReadTransaction (SecondaryIndex)
- (YapDatabaseSecondaryIndexTransaction *) secondaryIndexTransaction:(NSString *)extensionName
{
id extension = [self extension:extensionName];
if([extension isKindOfClass:[YapDatabaseSecondaryIndexTransaction class]]) {
return extension;
}
return nil;
}
@end
@jj0b Yeah, that's what I'm doing currently in some places - the line lengths increased significantly. ;)
@sbooth's extensions make the Swift way of retrieving the extensions a little cleaner though. Good idea.
What could slightly reduce verbosity would be to make the ext return a non-nullable result, since, to extend on @sbooth says, the developer should know what type the extension with the specified name is.
I have some vague ideas on using generics here or changing the way the extensions for transactions and connections are retrieved, but nothing solid to suggest and actually probably not worth the effort to make a few lines of code more kosher. ;)
I don't think the result from -ext: can be non-nullable because there is no guarantee an extension with the requested name exists. One could make the case that to ask for a non-registered extension is an error and should be handled by throwing but it seems to me that error handling is an area where Swift and ObjC have diverged. In ObjC it's natural to obtain nil but in Swift it's nicer to use try?.
It's a radical suggestion but I think making -ext: and -extension: private would be a good thing- albeit a breaking change. I see the fact that these selectors return a subclass of YapDatabaseExtensionTransaction as more of an implementation detail of the framework. Since YapDatabaseExtensionTransaction doesn't have any public API the caller is forced to cast the result (either directly as we've been doing in Swift or indirectly by nature of ObjC's flexibility) before it can be used.
Removing -ext: and -extension: wouldn't allow the use case where a caller introspected the return type and handled multiple types but I'm not sure if this is a common usage pattern for YapDB. In my project I always know the extension type I'm asking for.
This would force callers to access extensions via the categories on YapDatabaseReadTransaction and better enforce type safety.
@sbooth In my usage of YapDB I also always know which extension type I'm asking for as well. I don't however think it should be considered an error to ask for a non-registered extension because this is something that would commonly happen if you follow the practice outlined in the Wiki to do your view extension registration asynchronously. When you do that, there is a need to check if the view extension has been setup or not before you register your mappings for the database view. I think we do want -ext: to be nullable.