-
Notifications
You must be signed in to change notification settings - Fork 757
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
Topic improve as event #2871
Topic improve as event #2871
Conversation
Dictionary classes are very different in functionality, so it is better to provide a standard way to specify what kind it should be.
Key value pairs is the most straightforward interpretation. It matches `asDict`, and has a complement `asPairs`.
can you describe the changes in more detail? |
i vote it up |
yes, i can do this. Today i had an idea for a little improvement, I'll add that, too. |
For uniformity, not only `asDict` should have a class argument, but also its complements. This commit adds them.
And here comes some explanation. The best documentation of all this is in the Key Value Pairs helpfile. Somehow it doesn't turn up when I search for In short, this interface allows us to easily move between three very common data structures for parameters:
each have advantages and disadvantages. e.g. (2) you can use very well for ordered pattern matching in rule systems, but for lookup (3) is better. (2) is used in synth arguments. Dependent on what you want to do, it may matter what class the collection of dictionary is. E.g. strings shouldn't be used as keys in an IdentityDictionary if you need them for lookup. But for symbols, the more efficient lookup is IdentityDictionary. This PR allows us to specify which class to use. Also, it unifies the interface, so that you can expect the correct class as return vale in all cases. Finally, it implements |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you also implement the asEvent
shortcut on Dictionary
as well? I found myself wanting to use it while testing, and it makes sense to me to have it for completeness.
here's the test code I used in case anyone else wants to try:
(
a = [ 1, 2, 3, 4 ];
a.asAssociations; // creates an array of associations [ (1->2), (3->4) ]
a.asAssociations(Bag); // creates a Bag with the same associations
b = List[ 5, 6, 7, 8 ];
b.asAssociations(Array); // same effect as a.asAssociations above
a.asPairs; // returns self
a.asPairs(Dictionary); // returns a Dictionary [ (3->4), (1->2) ]
a.asPairs(Bag); // not very useful, but works
a.asDict({}, Dictionary); // creates a Dictionary with associations
a.asDict({}); // default: IdentityDictionary
a.asDict({}, Event); // creates an Event
b.asDictWith({}, Dictionary); // creates a Dictionary with associations
b.asDictWith({}); // default: IdentityDictionary
b.asDictWith({}, Event); // creates an Event
c = Dictionary[ 1->2, 3->4, 5->4 ];
c.asPairs; // an Array
c.asPairs(Bag); // a Bag, not very useful but it works
c.asDict({}, IdentityDictionary); // converts to IdentityDictionary
c.asDict({}, Event); // converts to Event
c.asDict({}, NodeMap); // NodeMap is also a type of Dictionary
c.asDict({}, Event)
a.asDict(nil, Event);
a.asEvent;
b.asDict(nil, Event);
b.asEvent;
)
@@ -296,12 +296,17 @@ Dictionary : Set { | |||
|
|||
isAssociationArray { ^false } | |||
|
|||
asPairs { | |||
^this.getPairs | |||
asPairs { |class| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class
here needs documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good! yes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved.
} | ||
|
||
asDict { | ||
^this | ||
asDict { arg mergeFunc, class; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you mind changing this arg
to pipes? (Or change pipes to args in asPairs
above, that seems to be file-consistent)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd only do this for the whole file. I'd prefer to keep the surrounding style, and change it some time in the future, all at once in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved (for now)
HelpSource/Classes/Dictionary.schelp
Outdated
method::asDict | ||
If no arguments are passed, return itself. This is part of the link::Reference/Key-Value-Pairs:: interface. | ||
argument::mergeFunc | ||
This argument is not used, but exists to make the method compatible. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we add "compatible with Collection.asDict" (with a link to that method)? This may be confusing out of context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, done.
@@ -929,6 +929,7 @@ SequenceableCollection : Collection { | |||
|
|||
asPoint { ^Point(this[0] ? 0, this[1] ? 0) } | |||
asRect { ^Rect(this[0] ? 0, this[1] ? 0, this[2] ? 0, this[3] ? 0) } | |||
asEvent { |mergeFunc| ^this.asDict(mergeFunc, Event) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs documentation.
this.pairsDo { |key, val| res.add(key -> val) } | ||
^res | ||
} | ||
|
||
asPairs { | ||
asPairs { |class| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this method needs documentation, now that it has an additional parameter that can be explained.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
@@ -44,7 +44,39 @@ CODE:: | |||
[\freq -> 452, \amp -> 0.2].asDict | |||
(freq: 452, amp: 0.2).asDict |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This example fails for me, I think because Dictionary:-asDict
should choose IdentityDictionary
as its default class like Collection:-asDict
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah yes!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems resolved
HelpSource/Classes/Dictionary.schelp
Outdated
:: | ||
|
||
method::asKeyValuePairs | ||
See asPairs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest adding a link here, I think, in case these methods ever get moved around and their definitions move apart.
This makes it work for all collections, also for Dictionaries.
… here you are. Thanks for the review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the quick response! This looks good to me now. Very slick.
This requires the method assertEvery in a separate pull request made for the UnitTesting quark.
Oof.. I'm really not a fan of adding an
Maybe we should have a conversation about this on the mailing list/dev call... I've only brought it up a few times but it seems like there is a significant difference among testing philosophies on this project and it might benefit from some discussion. |
I wrote The example test I did (independent of whether you agree on its value) shows that it makes it easy to combinatorially test large sets. Because a failure will post both the failed test function's source code and its index in the array, you can easily find which test has failed.
|
Oh! I missed that source code is also posted on failure, that changes things. Most other languages don't have this much introspection (I'm thinking of the effort that goes into stringifying source code / test names in the boost.test lib) so I'm trying to hold back from judging this idea by the APIs provided by other test libs.
Sorry, I'm not sure what distinguishes this as an "interface test", or why that would need special treatment. These are after all just methods sent to class instances. What I'm picking up on is that there some benefit to grouping these conversion methods in the same suite? How about a suite named specifically for that purpose,
No actually, I didn't fully understand what was going on at first, but now it makes more sense. The only thing I am still concerned about is that even though it's true that this "makes it easy to combinatorially test large sets," it has the potential to obfuscate test code since there are now multiple layers of indirection. Each layer makes it more difficult to verify at a glance that the tests are testing the right things. Since test code is inherently high-volume (and this case is no exception), and since test code should be the first guard against bugs, I consider that problematic. |
Changes: -move key-value-pairs tests to separate test class -use asserEquals and explicit iteration - add newFrom tests for collection conversion
ok, please take a look if that is better. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just really don't understand this testing approach, sorry... Why chain together 2-3 function calls? Why group three separately labeled sections in one test?
This one test (test_keyValuePairs) is now testing many different behaviors. It's more a matter of consistency than anything--is the "unit test" under consideration here a single method, or a single assert within a method? Is the "unit" one function call, or a single property of a group of function calls?
It seems to me that there are obvious benefits to preferring the former in both cases: modularity, clarity, self-documenting code, reduced chance of bugs, and conformance to existing testing patterns in this and other languages. For the latter cases, I don't see a strong benefit other than a reduction in lines of code.
@@ -0,0 +1,62 @@ | |||
TestConversions : UnitTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Conversions" could cover a lot of methods, not all of which should be grouped together IMO. Can we rename this TestCollectionConversions
? I think Collections are a good functionally contained unit to test on.
} | ||
|
||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing EOF newline
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
newline still needed.
(design decision waiting on method table size outcome) |
https://github.com/brianlheim/sclang-method-table-size/ See also my email to sc-dev. I say we are safe to proceed with freely adding methods; even if we had two test methods for every method in SC it wouldn't make much of an impact. The test suite doesn't ship with the binaries, so most users are unaffected anyway. What do you think @telephon ? |
@brianlheim better like this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Works for me, thanks!
@snappizz or someone else, want to take a look at this quick? I'm too tired to trust myself with merging this right now. :) |
@LFSaw maybe, as well? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked at the code and think it is in the state of merging.
Also, all comments by @brianlheim are resolved apart from the missing trailing newline in TestConversion.sc
@@ -44,7 +44,39 @@ CODE:: | |||
[\freq -> 452, \amp -> 0.2].asDict | |||
(freq: 452, amp: 0.2).asDict |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems resolved
this.pairsDo { |key, val| res.add(key -> val) } | ||
^res | ||
} | ||
|
||
asPairs { | ||
asPairs { |class| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved
@@ -296,12 +296,17 @@ Dictionary : Set { | |||
|
|||
isAssociationArray { ^false } | |||
|
|||
asPairs { | |||
^this.getPairs | |||
asPairs { |class| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved.
} | ||
|
||
asDict { | ||
^this | ||
asDict { arg mergeFunc, class; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved (for now)
} | ||
|
||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
newline still needed.
I can merge as soon as the newline appears :) |
Key value pairs is the most straightforward interpretation. It matches
asDict
, and has a complementasPairs
.I'd add the documentation when we have agreed on the correctness.