On 13 December 2012 08:16, Ciprian Teodorov <ciprian.teodorov@gmail.com> wrote:
On Thu, Dec 13, 2012 at 3:11 AM, Igor Stasenko <siguctua@gmail.com> wrote:
On 13 December 2012 03:08, Igor Stasenko <siguctua@gmail.com> wrote:
On 11 December 2012 20:33, Ciprian Teodorov <ciprian.teodorov@gmail.com> wrote:
Hi guys,
today I have commited to the NativeBoost repository a new core class, the NBExternalEnumerationType, which reifies the enum declarations in C and offers a nice interface (especially in terms of debug/inspect).
To use it just subclass the NBExternalEnumeration and add an #enumDecl method to the class side such as:
NBExternalEnumeration subclass: #NBTestEnumeration instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'NativeBoost-Tests'
NBTestEnumeration class>>enumDecl ^ {(#AAA -> 1). (#BBB -> 2). (#CCC -> 3). (#DDD -> 2400)} asDictionary
just one comment: imo, it would be better to not force users to remember that they should use complicated syntax in this method.
i propose following syntax:
NBTestEnumeration class>>enumDecl ^ #( #AAA 1 #BBB -> 2 #CCC -> 3 #DDD -> 2400 )
oops, of course it should be just pairs, e.g.: #( A 1 B 2 C 3) Yep this is a good idea for most cases so I'll integrate it. But there are those cases where your enum has many items (more than the number of literals we can have in a method), and I think in those cases having the user give us a prebuilt dictionary is better.
and where you see many literals? #( ..... no matter how many stuff here ... ) is 1 (single) literal! .. (i wonder, why people keep confusing literals in method body versus stuff in a single literal array :) And you don't have to trust my word, you can check it by yourself, just evaluate: | x | x := #(A B C). ^ thisContext method literals size versus: | x | x := #(A B C D E F G H I J K L M N). ^ thisContext method literals size
then you can have
NBTestEnumeration class>>initializeEnum
dict := Dictionary newFromPairs: self enumDecl .....
then #initialize should just do 'self initializeEnum'
DO NOT FORGET to call the #initialize method on your class. The rest is automatically done ;)
You can use your new enum in two ways:
add it to a client class poolDictionaries list (see #NBExternalEnumTests for an example), and then just write CCC in your code -- CCC here is an item of your enum or you can send the name of an item to your class --- NBTestEnumeration DDD
The NBExternalEnumeration implements (instance and class) some more API methods like:
#itemAt: retrieves the item having a specific value --- NBTestEnumeration itemAt: 2 #includes: checks the existence of a specific item in the enum --- NBTestEnumeration includes: #AAA
Having this already gives us a nice interface to working with enums. Now I plan to improve a little bit on performance and usage scenarios:
the possibility to accept smalltalk integers as valid input/output for functions(or callbacks) that use enums as arguments/return. support the different representation types for the enum values (int/uint)
to my thinking, it not worth implementing separate type converter for enums.. just put a note that if people would like to deal nicely with enums returned by function(s), they should use a converter , something like that:
enumValue := MyEnumeration fromInteger: (self callSomeFunctionReturningInt)
This is a good idea too.
then this method can implement converting from int->enum object, as well as do a range checking etc. in same way, if people want to use 'enumValue' for passing it as parameter to external function, they should not pass it directly , but use 'enumValue value'
In general, it would be cool to have good 'enum type' converter.. (despite that i will never use it, because to my taste its not really worth it, and i can live with integers and in most cases you hide such low-level details from end-user anyways ;)) but for those, who want more clarity and better structure in their code, of course, they can use it .
I do not completely agree with you on this one (but you already now it). The thing is that if we use integers then the user will have to constantly ask which enum value should I pass here...
The idea is to not expose enum values to user at all. Sometimes it easily doable, sometimes not.. it depends , of course.. But ideally, there should be only messages.
If you want that you can always have it by declaring your function signature as #(void fct(int anEnumValue)) and then call it with MyEnum DDD value (that's fine). Having an enum type converter is very good for documenting the argument types (and automatically checking them).
True. But everything has its cost: in this case - performance.
So I think this should be the user choice. Moreover, I'm for incremental development (and learning) so the way I see it is: When you first implement the ffi wrapper just try to be as precise as you can be, then after your library binding is done you can change some declarations to use more 'low level types' (the underlying representation) for speed reasons mainly (if it ever comes to that).
Yes.
But at the end I think we should give our users options, which will help them make decisions based on their particular needs, not based on our "gut" feeling ;)
I agree that this will be nice addition: for better coverage alien (C) data structures. I am totally with you on that. I just wanted to say that i never thought about it as a necessary part (simply because i can live without it). -- Best regards, Igor Stasenko.