progrium/darwinkit

darwinkit: 0.5.0-preview prepare tasks

progrium opened this issue · 16 comments

There is now a darwinkit branch that represents a major rewrite based on a heavily modified hsiafan/cocoa and a new symbols database I'm using that provides metadata for nearly every class, protocol, method, property, struct, enum, constant, union, macro, alias, and function across all Apple frameworks. This is not integrated yet, but that's the next step.

This issue is to track progress towards cutting a 0.5.0-preview release based on this branch. This pre-release will bring attention to the major breaking changes of the upcoming 0.5.0 release, solicit more feedback while things are in flux, and announce the intention to rename to DarwinKit with 0.5.0.

So what are the benefits of all this change? Here are some features of this new version:

  • Significantly greater generated class bindings coverage (currently 18x more, from ~80 to over 1500)
  • Generated enums and constants, currently at around 7k of them
  • Simpler, more powerful generation tooling with no dependency on macschema
  • Direct support of native Go builtin types like strings, bools, []byte, maps, etc in bindings
  • More 1-to-1 mapping to Objective-C symbol names while also improving Go idiomaticness
  • Support for block arguments as Go functions with properly typed arguments (callbacks!)
  • Pre-made delegate implementations you can simply set Go functions on
  • Documentation for all symbols including a link to official Apple docs on that symbol
  • Setting up to support multiple recent macOS versions
  • Setting up to support more platforms like iOS, watchOS, maybe visionOS
  • No more compile warnings
  • More examples
  • Closes a lot of open issues :)

Most of this is represented in this branch, but below will track what else needs to be done before 0.5.0-preview. Otherwise, I'm very interested in getting feedback and learning what questions people will have with this release. Please try this branch out, checking out all the new and ported examples and let me know they work on your platform.

TODO

  • use hsiafan/cocoa as new foundation, pulling in tons of bindings, block support, etc
  • fix methods returning slices
  • drop dependency on testify package
  • generate framework enums and constants
  • generate the few missing classes from current macdriver
  • add doc strings to generated types
  • switch away from oldgen and use new symbols database
  • new/updated readme
  • merge into clean main

This new branch sounds impressive. Great job making it.

I did noticed you use generics in your code. This means the official Go requirements will be at least 1.18 or higher. I will make it a note in the documentation once this branch is live.

Yes, good point, it will target Go 1.18+ now and that's worth mentioning in release notes.

I like how you changed the cocoa package's name to appkit.
How long did it take for you do all this work?

If a type begins with an I does it mean that type is a Go interface?

The action package's Set() method looks very familiar... I like it.

I tried the layout example program. When I tried to get the button object thru the sender variable I saw a panic. Is it still not possible?

This is what I tried:

	action.Set(dButton, func(sender objc.IObject) {
		// Trying to get the button
		button := sender.(appkit.Button)
		fmt.Println("Button:", button)

		d := widgets.NewDialog(400, 300)
		d.SetView(appkit.NewLabel("test dialog"))
		d.Center()
		d.Show(func() {
			fmt.Println("ok!")
		})
	})

The action.Wrap() function is a very good idea. I was actually working on the same thing and was in the testing phase when DarwinKit showed up.

If a type begins with an I does it mean that type is a Go interface?

Correct. This is not a common thing to do in Go, usually you would not have an interface type with the same name as a concrete type. However, we need both for every framework type.

I tried the layout example program. When I tried to get the button object thru the sender variable I saw a panic. Is it still not possible?

The FFI code allowing callbacks and blocks doesn't work with interfaces right now, so the rule is interfaces are only for method arguments. But callbacks need to use concrete types. Try an appkit.Button as the argument. And if it still doesn't work, submit a separate issue with the specific line the panic happens and full source.

I tried the layout example program. When I tried to get the button object thru the sender variable I saw a panic. Is it still not possible?

The FFI code allowing callbacks and blocks doesn't work with interfaces right now, so the rule is interfaces are only for method arguments. But callbacks need to use concrete types. Try an appkit.Button as the argument. And if it still doesn't work, submit a separate issue with the specific line the panic happens and full source.

I found an easy fix for this issue. Create another function that does take the NSControl subclass as an argument. This is the updated action.Set() method:

// Set set action for an ojbc instance, if it has target and setAction method.
func Set(instance CanSet, handler Handler) {
	newFunc := func(sender objc.IObject) {
		handler(instance)
	}
	target, selector := Wrap(newFunc)
	defer target.Release()
	objc.SetAssociatedObject(instance, objc.AssociationKey("target"), target, objc.ASSOCIATION_RETAIN)
	instance.SetTarget(target)
	instance.SetAction(selector)
}

Now I am able to get the button thru the sender argument.

I found an easy fix for this issue. Create another function that does take the NSControl subclass as an argument. This is the updated action.Set() method:

I'm confused. The code shown uses the same argument type you used in your previous code. If you're actually using appkit.Control or appkit.Button, you could just use that in your callback and no modification of the helper is needed. Can you create a separate issue if there is still confusion?

Where is NSMakeRect()?

Where is NSMakeRect()?

This is a function, which historically we haven't had bindings for. However, I'm looking to get them in this time around. Previously, we had a Go function equivalent but it was just a native Go function that returns a struct. Since I'm hoping to get the actual NSMakeRect generated, I haven't included a Go version, but you can see in the examples there is a version you could use or make yourself (rectOf).

How does someone help provide bindings for functions and classes to DarwinKit?

There will be documentation, but I'm still getting the system in place.

I see a macos folder in DarwinKit. Will there be other folders like watchos, iOS, iPadOS, and tvOS?

If you don't drive me insane before then.

Finished all the todos here, so merging into main.

PR for going into main:
#176

Remaining tasks for preview release tracked here:
#177