Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make breaking changes needed to support arrays of primitives #5149

Merged
merged 7 commits into from
Aug 24, 2017

Conversation

tgoyne
Copy link
Member

@tgoyne tgoyne commented Jul 20, 2017

Everything but the last commit is just pulling in latest master and #5148 on top of master-3.0.

This makes the two API changes needed for arrays of primitives: loosening the generic constraint to allow non-RLMObjects in RLMArray/RLMResults (but not yet actually supporting anything else), and changing RLMProperty/RLMPropertyType so that arrays of things other than objects can be expressed.

@tgoyne tgoyne self-assigned this Jul 20, 2017
@bdash
Copy link
Contributor

bdash commented Jul 21, 2017

Shouldn't we pull in the changes from master (and #5148, once it's merged to master) via a merge commit, rather than rebasing as you appear to have done here?

@tgoyne
Copy link
Member Author

tgoyne commented Jul 21, 2017

Yes, but that merge should be from master so it needs #5148 to be merged first.

if (![array->_objectClassName isEqualToString:object->_objectSchema.className]) {
@throw RLMException(@"Object type '%@' does not match RLMArray type '%@'.",
object->_objectSchema.className, array->_objectClassName);
- (RLMResults *)sortedResultsUsingProperty:(NSString *)property ascending:(BOOL)ascending {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be completely removed for 3.0.

@@ -387,7 +435,7 @@ - (id)maxOfProperty:(NSString *)property {

- (id)sumOfProperty:(NSString *)property {
[self validateAggregateProperty:property method:_cmd allowDate:false];
return [_backingArray valueForKeyPath:[@"@sum." stringByAppendingString:property]];
return [_backingArray valueForKeyPath:[@"@sum." stringByAppendingString:property]] ?: @0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Foundation's @sum returns nil for an empty array, shouldn't we match that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We decided not to match Foundation's behavior because Foundation is wrong; the sum of an empty set isn't undefined.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I vaguely remember this discussion, but not the outcome. thanks for clarifying.

// get object class from type string - @"RLMArray<objectClassName>"
_objectClassName = [[NSString alloc] initWithBytes:code + arrayPrefixLen
length:strlen(code + arrayPrefixLen) - 2 // drop trailing >"
encoding:NSUTF8StringEncoding];

if ([RLMSchema classForString:_objectClassName]) {
_optional = false;
_type = RLMPropertyTypeArray;
_type = RLMPropertyTypeObject;
return YES;
}
@throw RLMException(@"Property '%@' is of type 'RLMArray<%@>' which is not a supported RLMArray object type. "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This exception message is incorrect now "RLMArrays can only contain instances of RLMObject subclasses."


if (property.type == RLMPropertyTypeArray || property.type == RLMPropertyTypeLinkingObjects)
if (property.array || property.type == RLMPropertyTypeLinkingObjects)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RLMPropertyTypeLinkingObjects properties have array set to true, so this check can just be if (property.array)

return YES;
}
if (array) {
if (RLMArray *array = RLMDynamicCast<RLMArray>(value)) {
return [array.objectClassName isEqualToString:objectClassName];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this need to consider primitive types?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this PR does not add support for arrays of primitives.

return [array.objectClassName isEqualToString:objectClassName];
}
if (RLMListBase *list = RLMDynamicCast<RLMListBase>(value)) {
return [list._rlmArray.objectClassName isEqualToString:objectClassName];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this need to consider primitive types?

@tgoyne tgoyne force-pushed the tg/relax-collection-constraints branch 2 times, most recently from f4664c2 to db1e356 Compare August 2, 2017 18:26
@tgoyne tgoyne force-pushed the tg/relax-collection-constraints branch from db1e356 to f80f7fb Compare August 10, 2017 23:23
@tgoyne tgoyne force-pushed the tg/relax-collection-constraints branch from f80f7fb to 4943c8f Compare August 21, 2017 22:12
public override func value(forKey key: String) -> Any? {
return value(forKeyPath: key)
*/
@nonobjc public func value(forKey key: String) -> [AnyObject] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does @nonobjc mean that this cannot be invoked from Obj-C? I'd think that would give unexpected behavior from calls to -valueForKeyPath: with a key path that traverses into a List but where the List isn't the root object.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invoking it from obj-c calls the one defined on the parent class which does the exact same thing. This function just refines the return type when calling it from from Swift to make the code using it a little less awkward.

@@ -123,6 +122,11 @@ private func forceCast<A, U>(_ from: A, to type: U.Type) -> U {
return from as! U
}

/// A type which can be stored in a Realm List or Results
public protocol RealmCollectionValue {
static func className() -> String
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What will this return for primitive types?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function has actually gone away on the primitive arrays branch because different functions were needed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like CI is failing due to this function being undocumented:

Undocumented Realm swift declarations:
{
  "warnings": [
    {
      "file": "/Users/realm/workspace/objc_pr/configuration/Release/target/docs/xcode_version/8.3.3/RealmSwift/RealmCollection.swift",
      "line": 127,
      "symbol": "RealmCollectionValue.className()",
      "symbol_kind": "source.lang.swift.decl.function.method.static",
      "warning": "undocumented"
    }
  ],

assertThrows(array.swap(index1: 0, -1))
assertThrows(array.swap(index1: 1000, 0))
assertThrows(array.swap(index1: 0, 1000))
assertThrows(array.swap(-1, 0))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Swift 4, the equivalent method on Array appears to be called swapAt.

// swiftlint:disable:next line_length
XCTAssertEqual(objectSchema.description, "SwiftObject {\n\tboolCol {\n\t\ttype = bool;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tintCol {\n\t\ttype = int;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tfloatCol {\n\t\ttype = float;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tdoubleCol {\n\t\ttype = double;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tstringCol {\n\t\ttype = string;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tbinaryCol {\n\t\ttype = data;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tdateCol {\n\t\ttype = date;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tobjectCol {\n\t\ttype = object;\n\t\tobjectClassName = SwiftBoolObject;\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = YES;\n\t}\n\tarrayCol {\n\t\ttype = array;\n\t\tobjectClassName = SwiftBoolObject;\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n}")
// XCTAssertEqual(objectSchema.description, "SwiftObject {\n\tboolCol {\n\t\ttype = bool;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tintCol {\n\t\ttype = int;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tfloatCol {\n\t\ttype = float;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tdoubleCol {\n\t\ttype = double;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tstringCol {\n\t\ttype = string;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tbinaryCol {\n\t\ttype = data;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tdateCol {\n\t\ttype = date;\n\t\tobjectClassName = (null);\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n\tobjectCol {\n\t\ttype = object;\n\t\tobjectClassName = SwiftBoolObject;\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = YES;\n\t}\n\tarrayCol {\n\t\ttype = array;\n\t\tobjectClassName = SwiftBoolObject;\n\t\tlinkOriginPropertyName = (null);\n\t\tindexed = NO;\n\t\tisPrimary = NO;\n\t\toptional = NO;\n\t}\n}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this needs to be updated?

Copy link
Contributor

@austinzheng austinzheng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good to me. I have no feedback of any real significance.

CHANGELOG.md Outdated
@@ -99,6 +99,13 @@ x.x.x Release notes (yyyy-MM-dd)
correctly nil out nullable properties when updating an existing
object when the `value` argument specifies nil or `NSNull` for
the property value.
* Rename `List.remove(objectAtIndex:)` to `List.remove(at:)` to match the named
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"name"

@@ -78,34 +78,28 @@ - (void)dealloc {
_observationInfo = nullptr;
}

static id cooerceToObjectType(id obj, Class cls, RLMSchema *schema) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"coerce"

@@ -314,14 +314,16 @@ public final class List<T: Object>: ListBase {

- parameter index: The index at which to remove the object.
*/
public func remove(objectAtIndex index: Int) {
public func remove(at index: Int) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Swift standard library version of this method returns the removed element. I don't know if this is something we should replicate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's sort of gratuitous overhead for something that's at best vaguely convenient, but matching the standard library is probably the way to go.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like Array returns the value that was there, but Collection/RangeReplaceableCollection don't and there's alternative functions on Collection for remove and return old (popLast() etc.), so I'm inclined to leave it as a void return.

@tgoyne tgoyne force-pushed the tg/relax-collection-constraints branch 3 times, most recently from ba37482 to 215909c Compare August 22, 2017 22:08
@bdash
Copy link
Contributor

bdash commented Aug 24, 2017

The changelog entries will need to be moved into the section for the upcoming section now that v3.0.0-beta.3 has been released.

@tgoyne tgoyne force-pushed the tg/relax-collection-constraints branch from 2caba93 to 719ded8 Compare August 24, 2017 01:32
@tgoyne
Copy link
Member Author

tgoyne commented Aug 24, 2017

Failures are both CI things that passed before updating the changelog.

@tgoyne tgoyne merged commit 7d9f20e into master-3.0 Aug 24, 2017
@bmunkholm bmunkholm deleted the tg/relax-collection-constraints branch March 12, 2019 13:05
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants