Best practice to partially implement an interface - go

What would be the go-way of partly providing a default implementation?
To illustrate, the following simple example of a toggle switch driver is the dead-end I ended with by following my OO intuition... Of course it does not compile (I know why) and I am not necessarily willing to do so. Any other solution better fitting into the go philosophy would be in fact even better to correctly understand the go-way for this common need.
The complete example can also be found at https://play.golang.org/p/MYED1PB-dS
Given the following interface:
type ToggleSwitch interface {
TurnOn()
TurnOff()
IsOn() bool
Toggle()
}
Toggle() is a good candidate to be provided a default implementation (ie, according to the current state, turn on or off the switch):
// The Toggle() method can already be defined using TurnOn, TurnOff() and IsOn().
type DefaultDriver struct {
}
// The following implementation would be fine for non-optimized cases:
func (d *DefaultDriver) Toggle() {
state := d.IsOn()
fmt.Println("generic toogle ->", state)
if state {
d.TurnOff()
} else {
d.TurnOn()
}
}
And then an actual driver could use it or not:
// Example of an actual ToggleDriver which should fully implement the interface
// based on the default implementation or not.
// For example, if the toggle switch device has a bult-in toggle command, the
// Toggle() method could be optimized to directly use it.
type DummyDriver struct {
*DefaultDriver // promote DefaultDriver methods
state bool
}
func (d *DummyDriver) IsOn() bool {
return d.state
}
func (d *DummyDriver) TurnOff() {
d.state = false
}
func (d *DummyDriver) TurnOn() {
d.state = false
}
// Uncomment me to optimize me...
//func (d *DummyDriver) Toggle() {
// fmt.Println("specialized toogle ->", d.state)
// d.state = !d.state
//}

Personnally, I would implement the Toggle, IsOn, TurnOn and TurnOff methods for the DefaultDriver type, so it would satisfy the ToggleSwitch interface.
Then, the DummyDriver type would embed the DefaultDriver type.
This way, you could implement the specialized methods for the DummyDriver type, as you desire.
The result would be something along these lines:
package main
import "fmt"
type ToggleSwitch interface {
TurnOn()
TurnOff()
IsOn() bool
Toggle()
}
type DefaultDriver struct {
state bool
}
func (d *DefaultDriver) Toggle() {
state := d.IsOn()
fmt.Println("generic toogle ->", state)
if state {
d.TurnOff()
} else {
d.TurnOn()
}
}
func (d *DefaultDriver) IsOn() bool {
return d.state
}
func (d *DefaultDriver) TurnOff() {
d.state = false
}
func (d *DefaultDriver) TurnOn() {
d.state = true
}
type DummyDriver struct {
DefaultDriver
state bool
}
// Uncomment me to optimize me...
//func (d *DummyDriver) Toggle() {
// fmt.Println("specialized toogle ->", d.state)
// d.state = !d.state
//}
func main() {
d := DummyDriver{state: false}
d.Toggle()
d.Toggle()
d.Toggle()
}
https://play.golang.org/p/Xm-8A0xoRb

In my opinion what you're trying to do isn't very Go-like.
ToggleSwitch defines four methods that clearly work on some state. In order to provide an implementation for any of these methods, you also need to implement that state (even if that state's non-existent, e.g. by defining those methods as no-ops), but at that point, it simply doesn't make sense not to provide all those methods.
With Go-like type composition the embedded types should generally be "whole", complete and useful on their own. Methods provided by the embedded type only work on that field alone, there's no way to get to the "parent" or its methods.
If ToggleSwitch also had other methods that didn't deal with that state, then it'd make sense to provide only a partial implementation of the interface, but at that point an even better and much more idiomatic solution would be to define ToggleSwitch as a combination of two separate interfaces.
In other words, I don't think there's a "Go way" to provide a partial implementation of an interface (that's not composed of several interfaces), because it's idiomatic in Go to define interfaces that are as small as possible.

Related

How to extend fyne BaseWidget - go gives error "type *SimpleCard has no field or method super"

I'm trying to extend fyne widget to have a simple clickable content with background.
I searched fyne widgets to find an example that could be used as a starter and found something similar in List/ListItem.
I basically copied the list item code and adapted it a little bit.
It does look similar to the simpler example on fyne documentation.
But for some unknown reason go gives me an error and I don't know what the cause is or how I can fix it:
custom_widget/simple_card.go:80:24: c.card.super undefined (type *SimpleCard has no field or method super)
Here is the code of the module (custom_widget/simple_card.go):
package custom_widget
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"log"
)
// Declare conformity with interfaces.
var _ fyne.Widget = (*SimpleCard)(nil)
var _ fyne.Tappable = (*SimpleCard)(nil)
type SimpleCard struct {
widget.BaseWidget
onTapped func()
background *canvas.Rectangle
content fyne.CanvasObject
selected bool
}
func NewSimpleCard(content fyne.CanvasObject, tapped func()) *SimpleCard {
card := &SimpleCard{onTapped: tapped, content: content}
card.ExtendBaseWidget(card)
return card
}
// CreateRenderer is a private method to Fyne which links this custom_widget to its renderer.
func (c *SimpleCard) CreateRenderer() fyne.WidgetRenderer {
c.ExtendBaseWidget(c)
c.background = canvas.NewRectangle(theme.SelectionColor())
c.background.Hide()
objects := []fyne.CanvasObject{c.background, c.content}
// NewBaseRenderer and BaseRenderer are copied from
// https://github.com/fyne-io/fyne/blob/master/internal/widget/base_renderer.go
// because the functionality is marked internal in fyne !?
return &SimpleCardRenderer{NewBaseRenderer(objects), c}
}
func (c *SimpleCard) Tapped(_ *fyne.PointEvent) {
log.Println("I have been tapped")
if c.onTapped != nil {
c.selected = true
c.Refresh()
c.onTapped()
}
}
// Declare conformity with the WidgetRenderer interface.
var _ fyne.WidgetRenderer = (*SimpleCardRenderer)(nil)
type SimpleCardRenderer struct {
BaseRenderer
card *SimpleCard
}
// MinSize calculates the minimum size of a SimpleCardRenderer.
// This is based on the size of the status indicator and the size of the child object.
func (c *SimpleCardRenderer) MinSize() fyne.Size {
return c.card.content.MinSize()
}
// Layout the components of the SimpleCardRenderer custom_widget.
func (c *SimpleCardRenderer) Layout(size fyne.Size) {
c.card.background.Resize(size)
c.card.content.Resize(size)
}
func (c *SimpleCardRenderer) Refresh() {
if c.card.selected {
c.card.background.FillColor = theme.SelectionColor()
c.card.background.Show()
} else {
c.card.background.Hide()
}
c.card.background.Refresh()
canvas.Refresh(c.card.super()) // compiler error !
}
Remove all of the renderer type you created and in the CreateRenderer just return widget.NewSimpleRenderer(container .NewMax(c.background, c.content)). It is simpler than you think.
Copying code out of the main widgets is often not the best way as we have shortcuts and/or must support more functionality than your own widgets.

How should I initialize interface types from the windows crate?

I have a struct that uses some types from the windows crate, but I'm not able to initialize them:
use windows::Win32::{
IUIAutomationFocusChangedEventHandler, IUIAutomationFocusChangedEventHandler_Vtbl,
};
// Here's my struct:
pub struct EventHandler {
// A struct member to handle the event:
event: IUIAutomationFocusChangedEventHandler,
event_vtbl: IUIAutomationFocusChangedEventHandler_Vtbl,
}
// Anyone with experience in the windows API
// Will understand the Virtual tables, and this code.
impl EventHandler {
pub fn new() -> EventHandler {
// Here, I should return a new instance of my struct:
EventHandler {
// Now, I should initialize every struct member:
event: IUIAutomationFocusChangedEventHandler {}, // ...
event_vtbl: IUIAutomationFocusChangedEventHandler_Vtbl {
// This struct needs two members:
base__: IUnknown {}, // IUnknown requires a lot of
// methods and member initialization to initialize it.
// Also the IUIAutomationFocusChangedEvent needs too member initialization....
},
}
}
}
These structs shouldn't be initialized in C++ winapi. I don't know what should I do. Every struct needs member initialization, and every member needs other members, and other members need member initialization!
I feel like I'm in a whirlpool! Am I missing something?
Answering the literal question first: You could, but you probably shouldn't have to.
COM support in the windows crate exposes many types, and not all of them are meant for immediate use by client code. The *_Vtbl structures specifically represent the raw function pointer tables used by COM internally to dispatch interface calls. They are declared and populated by the library and not intended to be used by clients directly (the #[doc(hidden)] attribute is a hint, though I'm sure the library structure and documentation experience can be improved).
Attempting to populate the v-tables in client code puts you into a miserable situation. Luckily, none of that is required, as briefly explained in the FAQ:
How do I implement an existing COM interface?
If you need to implement a COM interface for a type, you'll need to add the implement feature which (like any Cargo feature) can be enabled in your project's Cargo.toml file.
windows = { version = "..", features = ["implement"] }
Then you'll need to declare that your type implements a particular interface by adding the #[implement] proc macro to your type and then writing an impl block for the interface. For an interface called IMyInterface you will need to implement the IMyInterface_Impl trait (note the trailing _Impl in the name).
#[windows::core::implement(IMyInterface)]
struct MyStruct;
impl IMyInterface_Impl for MyStruct {
fn MyMethod(&self) -> windows::core::HRESULT {
todo!("Your implementation goes here");
}
}
Version 0.37.0 made significant changes to the implement macro, making this far more approachable than it may appear. Let's start out by declaring a simple structure with a bit of state information:
#[implement(IUIAutomationFocusChangedEventHandler)]
struct EventHandler {
count: Cell<u64>,
}
impl EventHandler {
fn new() -> Self {
Self {
count: Cell::new(0),
}
}
/// Increments the count and returns the new value
fn increment(&self) -> u64 {
let new_val = self.count.get() + 1;
self.count.set(new_val);
new_val
}
}
This keeps a cumulative count of focus change events that happened. Note that the implementation isn't actually correct: Since the event handler can be called from multiple threads we'd actually need a type that's Sync (which Cell isn't). That's something you'd need to change1.
What's missing is the IUIAutomationFocusChangedEventHandler interface implementation. It only has a single member, so that's easy (the IUnknown implementation is conveniently provided for you by the library already):
impl IUIAutomationFocusChangedEventHandler_Impl for EventHandler {
fn HandleFocusChangedEvent(&self, _sender: &Option<IUIAutomationElement>) -> Result<()> {
let count = self.increment();
println!("Focus changed (cumulative count: {})", count);
Ok(())
}
}
For every focus change event it first increments the cumulative count and then prints a message to STDOUT.
That's all that's required to implement a custom IUIAutomationFocusChangedEventHandler interface. Using that from a program isn't much harder, either, even though there are a lot of pitfalls (see comments):
fn main() -> Result<()> {
// Initialize COM for the current thread. Since we are running event handlers on this
// thread, it needs to live in the MTA.
// See [Understanding Threading Issues](https://learn.microsoft.com/en-us/windows/win32/winauto/uiauto-threading)
// for more information.
unsafe { CoInitializeEx(ptr::null(), COINIT_APARTMENTTHREADED) }?;
// Instantiate a `CUIAutomation` object
let uia: IUIAutomation =
unsafe { CoCreateInstance(&CUIAutomation, None, CLSCTX_INPROC_SERVER) }?;
// Subscribe to the focus changed event; this transfers ownership of `handler` into
// `uia`, making it the sole owner
let handler = EventHandler::new();
unsafe { uia.AddFocusChangedEventHandler(None, &handler.into()) }?;
// Display a message box so that we have an easy way to quit the program
let _ = unsafe {
MessageBoxW(
None,
w!("Click OK to end the program"),
w!("UIA Focus Monitor"),
MB_OK,
)
};
// Optionally unsubscribe from all events; this is not strictly required since we have
// to assume that the `CUIAutomation` object properly manages the lifetime of our
// `EventHandler` object
unsafe { uia.RemoveAllEventHandlers() }?;
// IMPORTANT: Do NOT call `CoUninitialize()` here. `uia`'s `Drop` implementation will
// get very angry at us when it runs after COM has been uninitialized
Ok(())
}
To compile the code you'll want to use the following imports:
use std::{cell::Cell, ptr};
use windows::{
core::{implement, Result},
w,
Win32::{
System::Com::{
CoCreateInstance, CoInitializeEx, CLSCTX_INPROC_SERVER, COINIT_APARTMENTTHREADED,
},
UI::{
Accessibility::{
CUIAutomation, IUIAutomation, IUIAutomationElement,
IUIAutomationFocusChangedEventHandler, IUIAutomationFocusChangedEventHandler_Impl,
},
WindowsAndMessaging::{MessageBoxW, MB_OK},
},
},
};
and this Cargo.toml file:
[package]
name = "uia_focus_change"
version = "0.0.0"
edition = "2021"
[dependencies.windows]
version = "0.39.0"
features = [
"implement",
"Win32_Foundation",
"Win32_System_Com",
"Win32_UI_Accessibility",
"Win32_UI_WindowsAndMessaging",
]
1 Possible alternatives include an AtomicU64 and a Mutex. An atomic is perfectly sufficient here, is easy to use, and will properly work in situations of re-entrancy:
use std::sync::atomic::{AtomicU64, Ordering};
#[implement(IUIAutomationFocusChangedEventHandler)]
struct EventHandler {
count: AtomicU64,
}
impl EventHandler {
fn new() -> Self {
Self {
count: AtomicU64::new(0),
}
}
/// Increments the count and returns the new value
fn increment(&self) -> u64 {
self.count.fetch_add(1, Ordering::SeqCst) + 1
}
}
A mutex, on the other hand, is substantially harder to use, its behavior in part unspecified, and equipped with lots of opportunities to fail. On the upside it is more versatile in protecting arbitrarily large structures:
use std::sync::Mutex;
#[implement(IUIAutomationFocusChangedEventHandler)]
struct EventHandler {
count: Mutex<u64>,
}
impl EventHandler {
fn new() -> Self {
Self {
count: Mutex::new(0),
}
}
/// Increments the count and returns the new value
fn increment(&self) -> u64 {
let mut guard = self.count.lock().expect("Failed to lock mutex");
*guard += 1;
*guard
}
}
Either one works and is compatible with COM objects that live in the MTA.

Sharing Domain Logic for Embedded Structs

I have a number of structs that share some common properties and logic, but I haven't been able to find a way to share logic that works. Basically, I have a file as part of a package that handles "widgets". I wanted to have a general Widget struct that's embedded in each specified widget struct WidgetA and WidgetB, then share a bit of logic during the creation process. For example:
type Widget struct {
name string
}
type WidgetA struct {
Widget
inspector string
}
type WidgetB struct {
Widget
length int
height int
}
func (w *Widget) Init() {
// Do some shared things
// Then figure out which _type_ of Widget this is and delegate
// to the appropriate receiver function
}
func (wa *WidgetA) Create () { ... }
func (wb *WidgetB) Create () { ... }
On the calling end, maybe something like this:
widgetA := &WidgetA{}
widgetA.Init()
I can't find a working solution to share the logic in Go, so I'd like to either understand where I'm going wrong or, if I'm going wrong be trying to apply old habits where they don't belong, figure out the most idiomatic way of accomplishing the same goal using Go.
Insight appreciated!
You can do something like this:
func (w *Widget) Init() {...}
func (wa *WidgetA) Init() {
wa.Widget.Init()
// init widgetA
}
func (wb *WidgetB) Init() {
wb.Widget.Init()
// init widgetB
}
widgetA:=WidgetA{}
widgetA.Init()
If you don't know the type of the object you're initializing, you can use an interface:
type Initer interface {
Init()
}
func f(w Initer) {
w.Init() // Call the Init() for the underlying widget type
}

Swift Type Inference Not Working (Xcode 7.1.1)

This is my first question on StackOverflow so please go easy on me.
I've been struggling with getting Swift to invoke the appropriate generic overload.
Suppose I have the following protocol -
protocol MyProtocol { }
And I have the following generic methods -
func foo<T>() -> T
func foo<T: MyProtocol>() -> T
One would expect that invoking foo() with a return type of T conforming to MyProtocol would invoke the appropriate overload.
let bar: MyProtocol = foo()
The above code actually invokes the following function during runtime and Cmd + Click in the IDE navigates to the wrong overload as well.
func foo<T>() -> T
For some reason I cannot get this to work properly in Xcode 7.1.1.
Am I missing something completely fundamental here or is this another Swift quirk?
EDIT
Adding an example of this behavior in action as per matt's request.
protocol MyProtocol { }
class MyProtoClass : MyProtocol { }
class Bar {
func foo<T>(value: T) {
print("T is Generic")
}
func foo(value: MyProtocol) {
print("T conforms to MyProtocol")
}
}
class MyClass<T> {
var value: T
init(value: T) { self.value = value }
var b = Bar()
func print() {
b.foo(value)
}
}
MyClass<MyProtocol>(value: MyProtoClass()).print()
MyClass<String>(value: "").print()
Copying and pasting the above code into a Swift command line application and executing yields the following output.
T is Generic
T is Generic
I think the problem here is that protocols in generics (and generally in Swift) don't work the way you want them to. They are not acting as first-class types. I know that's rather vague... but look at it this way; if you eliminate the func foo<T>(value: T) version of foo, your code won't even compile. In other words, Swift isn't making a choice of foo and choosing wrong; it's saying that b.foo(a1.value) does not call func foo<T: MyProtocol>(value: T).
I have a vague feeling that this is related to my question here:
Protocol doesn't conform to itself?
Okay, I am going to answer my own question here.
After some investigation it seems that Swift wants you to implement an extension with a type constraint on the generic parameter.
extension MyClass where T : MyProtocol {
func print() {
b.foo(value)
}
}
I know this doesn't really solve the problem but it was sufficient enough for me as a work around in my real world use case.
The above sample would wind up looking something like the following.
protocol MyProtocol { }
class MyProtoClass : MyProtocol { }
class Bar {
func foo<T>(value: T) {
print("T is Generic")
}
func foo(value: MyProtocol) {
print("T conforms to MyProtocol")
}
}
class MyClass<T> {
var value: T
init(value: T) { self.value = value }
var b = Bar()
func print() {
b.foo(value)
}
}
extension MyClass where T : MyProtocol {
func print() {
b.foo(value)
}
}
MyClass<MyProtoClass>(value: MyProtoClass()).print()
MyClass<String>(value: "").print()

call swift optional protocol method in super

I'd like to make an NSView subclass that handles drag and drop by redirecting it to its view controller. So I have to override NSDraggingDestination protocol methods in my NSView subclass. There I'd like to check if method is supported by view controller implementation and call it, or if not supported to call base class implementation. The first part seems easy by optional chaining, but how do I check if method implemented in super class? For example, this is what I came up for draggingEnded method. It gives a runtime crash inside if block, if the view controller does not implement draggingEnded method.
class ControllerChainedView: NSView {
#IBOutlet weak var chainedController: NSViewController!
override func draggingEnded(sender: NSDraggingInfo?) {
let destination = chainedController as! NSDraggingDestination
if !(destination.draggingEnded?(sender) != nil) {
super.draggingEnded(sender);
}
}
}
Changing the line inside if to super.draggingEnded?(sender); gives a compiler error. (Operand of postfix '?' should have optional type; type is '(NSDraggingInfo?) -> Void')
There is no problem with say similar draggingEntered method as it seems to be implemented in NSView.
So the question is how to detect if one can call method in super or not?
If your super is based on NSObject, you can still use respondsToSelector: in this way:
if super.respondsToSelector("draggingEnded:") {
super.draggingEnded(sender)
}
UPDATE - based on 1st Alex comment
Depends. Generally no, you can't do this with optional chaining without calling it.
But what you can do is to check if function was or wasn't called. But again, in specific cases only. Must be #objc protocol, must be based on NSObject and return value of optional function must not be Optional.
Check following examples.
#objc protocol Opt {
optional func implemented() -> Void
optional func notImplemented() -> Void
}
class Object: NSObject, Opt {
func implemented() {}
}
let o = Object() as Opt
let implementedCalled = o.implemented?() != nil // == true
let notImplementedCalled = o.notImplemented?() != nil // == false
In this particular case, implementedCalled is set to true. In other words, you can at least check if method was called or not. It's because of optional chaining and because o.implemented return type is Void, o.implemented?() returns Void?.
You can also do something like this ...
if o.implemented != nil {
// Function is implemented AND implemented WAS CALLED
} else {
// Function is not implemented
}
... but don't forget that it's not check if function is implemented, it's - if function is implemented, call it and return .Some(Void) or .None if it's not implemented.
In your particular case, you can do this:
override func draggingEnded(sender: NSDraggingInfo?) {
let destination = chainedController as! NSDraggingDestination
if destination.draggingEnded?(sender) == nil {
// .None returned - method not implemented in destination
// draggingEnded is called in super only if it's implemented
// ignore result of type Void?
super.draggingEnded?(sender)
}
}
If return type of optional function is not Void, but for example String, it behaves in the same way.
#objc protocol Opt {
optional func name() -> String
}
class Object: NSObject, Opt {
func name() -> String { return "Object" }
}
let o = Object() as Opt
let n: String? = o.name?() // n contains "Object"
If name is not implemented, n will contain None.
So far, so good. We can check if function was called for Void and for String (or any other type).
But what if return type is Optional? String? for example.
#objc protocol Opt {
optional func name() -> String?
}
class Object: NSObject, Opt {
func name() -> String? { return nil }
}
class Object2: NSObject, Opt {
}
let o = Object() as Opt
let n = o.name?()
let o2 = Object2() as Opt
let n2 = o2.name?()
Object implements name, but it returns nil and Object2 does not implement name at all. But both n and n2 contain nil. In other words, if return type is Optional, we can't check if function is or isn't implemented.
As you can see, it's tricky. Sometimes it suits your needs, sometimes not. If you are sure that your object is based on NSObject, stick with .respondsToSelector to be safe. You can then ignore all these conditions and cases.
If your goal is to just call function if it's implemented and you don't care if it is really implemented or not, if you're not interested in result, you can do it with ?.
Since the optional syntax ? is not working for super you'll have to check explicitly whether the superclass implements the method.
if NSView.instancesRespondToSelector("draggingEnded:") {
super.draggingEnded(sender)
}

Resources