Open madsmtm opened 2 years ago
Also discussed previously in the metal
crate: https://github.com/gfx-rs/metal-rs/issues/190
I think we should stick with Objective-C naming at the very least until we can autogenerate documentation based on https://developer.apple.com/, since it's just much more discoverable that way - but I can be persuaded otherwise!
The windows
crate is also a good place to look to for how this is done elsewhere.
So far going through the Apple's documentation I've only came across one instance of where an instance method and type method has had the same name. The NSObject
protocol has an instance method called class
while the NSObject
interface has the type method class
.
What do you think about having suffixes for methods like ip_
for instance property and tp_
for type property?
instance method and type method
I'm a bit unsure about your terminology here; do you mean "instance method" and "protocol method"?
In general my opinion is that adding prefixes or suffixes is unnecessary - to the user, it doesn't really matter if something is a method or a property, or defined on a class or on a protocol, the way they're used is exactly the same.
Take for example +[NSThread isMainThread]
and +[NSThread isMultiThreaded]
: Here, the former is a property and the latter is a method, but I'd have no way of guessing which was which.
Similarly, I don't think we need to differentiate between class and instance methods, since their usage is different enough from Rust that it is already quite clear: NSThread::new()
calls a class method, while obj.name()
calls an instance method.
Of course, duplicate names do occur in such a way that we must change (e.g. NSThread
has both +[NSThread isMainThread]
and -[NSThread isMainThread]
), but I think they are rare enough that we can do it on a case-by-case basis (so e.g. have NSThread::class_is_main_thread()
and thread.is_main_thread()
).
I understand where your coming from and you made a good point :)
Another possibility is to namespace enums, structs and typedefs behind modules (when it makes sense):
mod ns_accessibility { struct AnnotationPosition(NSInteger) }
struct NSDirectionalEdgeInsets { fields* }
mod ns_bitmap_image_rep { struct PropertyKey(NSString) }
I considered namespacing the same was as Swift, e.g. mod NSBitmapImageRep { struct PropertyKey(NSString); }
, but we can't do that since it'd conflict with the NSBitmapImageRep
class (again, no way to make associated types on structs).
Though perhaps we could then do mod NSBitmapImageRep { struct Class(...); }
for classes instead?
cidre
uses the following scheme:
mod ns {
struct Array<T>; // NSArray
struct String; // NSString
struct Number; // NSNumber
}
// Usage
use cidre::ns;
let array: ns::Array<ns::String> = ns::Array::new();
Which works pretty good for Foundation, but I'm not sure how well it extends to e.g. AppKit?
I've pushed some of the objc2::runtime
types towards a more Swifty naming scheme in https://github.com/madsmtm/objc2/pull/463.
I've pondered this for a while now, but at this point I feel like sticking close to Objective-C for method and function names is the correct approach, even though it's less "Rusty".
That said, we still need to do some more work on the enum case prefix stripping, eliminating needless words in methods and on category naming.
Currently, I think the naming scheme is going to be:
objc2-foundation
struct NSObject
struct NSCopying
struct NSObjectProtocol
(renamed to not conflict with NSObject
)impl Foo {}
(inherent implementation)NSObject
: trait NSNibAwaking
(emit category name as-is)trait NSAffineTransformAdditions
(AppKitAdditions
)trait NSAccessibility
#[method(someMethod:withExtraParam:)] fn someMethod_withExtraParam(arg: i32, extra: u32)
#[method(aMethod:error:)] fn aMethod(arg: i32) -> Result<(), Id<NSError>>
#[method(aMethodWithCompletionHandler:)] async fn aMethod()
_class
when class methods conflict with instance methods.struct NSAccessibilityAnnotationPosition(NSInteger)
impl NSAccessibilityAnnotationPosition { const FullRange: Self = ... }
(the hope is that they will one day be closer to real enums)struct NSDirectionalEdgeInsets { fields* }
NS_TYPED_EXTENSIBLE_ENUM
, when possible: impl NSModalResponse { const Stop: NSModalResponse = ... }
const NSModalResponseStop: NSModalResponse = ...
type NSBitmapImageRepPropertyKey = NSString
extern "C" { static NSImageCurrentFrameDuration: NSBitmapImageRepPropertyKey }
extern "C" { fn NSBitsPerPixelFromDepth(depth: NSWindowDepth) -> NSInteger }
icrate
(or whatever it'll end up being named) is nearing an initial version, see https://github.com/madsmtm/objc2/pull/264.After that, we need to figure out how we should handle name translation for enums, method names, and so on. There are a few options:
Foundation
struct NSObject
struct NSCopying
trait NSAccessibility; impl NSAccessibility for NSObject;
(or perhapsNSObject_NSAccessibility
?)fn someMethod(arg: i32)
,fn someMethod_withExtraParam(arg: i32, extra: u32)
fn aMethod_error(arg: i32) -> Result<(), Id<NSError>>
async fn aMethodWithCompletionHandler(f: &Block<(), ()>)
, see also #279struct NSAccessibilityAnnotationPosition(NSInteger)
const NSAccessibilityAnnotationPositionFullRange: NSAccessibilityAnnotationPosition = ...
struct NSDirectionalEdgeInsets { fields* }
const NSModalResponseStop: NSModalResponse = 1000
struct NSBitmapImageRepPropertyKey(NSString)
extern "C" { static NSImageCurrentFrameDuration: NSBitmapImageRepPropertyKey }
extern "C" { fn NSBitsPerPixelFromDepth(depth: NSWindowDepth) -> NSInteger }
Foundation
fn some(method: i32)
,fn some_with(method: i32, extraParam: u32)
(name is significantly stripped)fn a(arg: i32) -> Result<(), Id<NSError>>
(error
postfix is removed)async fn a()
(WithCompletionHandler
stripped)struct NSAccessibilityAnnotationPosition(NSInteger)
, Swift usually creates a nested items likeNSAccessibility::AnnotationPosition
, but that is not possible in Rustimpl NSAccessibilityAnnotationPosition { const fullRange: Self = ... }
struct NSDirectionalEdgeInsets { fields* }
impl NSModalResponse { const stop: Self = 1000 }
struct NSBitmapImageRepPropertyKey(NSString)
impl NSBitmapImageRepPropertyKey { fn currentFrameDuration() -> &'static Self }
, associated statics are not possible in Rust yet so we must create a new function that can return it (also if we want to make it safe)impl NSWindowDepth { fn bitsPerPixel() -> NSInteger }
foundation
fn some_long_method_name(method: i32)
, method name is made always lowercase (note: difficult now to tell which selector it corresponds to)impl NSAccessibilityAnnotationPosition { const FULL_RANGE: Self = ... }
, constant is uppercaseimpl NSModalResponse { const STOP: Self = 1000 }
, constant is uppercaseimpl NSBitmapImageRepPropertyKey { fn current_frame_duration() -> &'static Self }
, function is made lowercase, in the future if we get associated statics then the name would change to be uppercaseimpl NSWindowDepth { fn bits_per_pixel() -> NSInteger }
, function is made lowercaseI like option 1 since it'll mean that things are more "searchable"/"grepable". This point also somewhat goes for option 2, though a bit less so, since Swift is newer. The downside to both of these is of course that the names don't really match Rust's naming conventions.
Implementation wise: Option 1 is already implemented, so that's easy. Option 2 has seen a lot of work already by Apple/Swift developers, and they've even created the
.apinotes
system to help with edge-cases. Option 3 would be quite easy on top of 2, but would require a bit extra work if we want to tweak names further afterwards.