Skip to content
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

What is the purpose of duplicate functions? #115

Open
mitchellwrosen opened this issue Apr 23, 2019 · 12 comments
Open

What is the purpose of duplicate functions? #115

mitchellwrosen opened this issue Apr 23, 2019 · 12 comments

Comments

@mitchellwrosen
Copy link
Contributor

For example, the Button module defines

  • handleButtonBase
  • resizeButtonBase
  • hideButtonBase
  • showWidgetButtonBase

but there also exists

  • impl ~ (Event -> IO (Either UnknownEvent ())) => Op (Handle ()) ButtonBase orig impl
  • etc.

with (as far as I can tell) the same types. Is there a difference between these? Thanks!

@deech
Copy link
Owner

deech commented Apr 23, 2019

It's so one can call base class methods. While the type signatures are the same the underlying method call is different.

@mitchellwrosen
Copy link
Contributor Author

I see... I'm still having some difficulty understanding. Which call is which? I'm not entirely clear on what BaseButton is, and the source you linked also mentions DerivedButton. However, neither of these are defined in FLTK proper, at least according to this diagram.

@mitchellwrosen
Copy link
Contributor Author

I read over the docs a bit more and I'm starting to understand. My understanding now is that in fltkhs, FooBase is Fl_Foo. The non-Base versions have no analogous class in C++. A Ref Foo, then, is exactly the same thing as a Ref FooBase (which is to say, has exactly the same API as, and whose functions behave identically to), except for the things you mentioned in #112.

@deech
Copy link
Owner

deech commented Apr 23, 2019

Yes exactly and I admit this is confusing. Basically the inheritance chain looks like:

ABase -> A
 |
 v
BBase -> B
 |
 V
CBase -> C
 |
 v

where A,B, and C are the widgets you construct and use. Notice it is impossible use the *new functions to create any Base widgets. The reason for this confusing architecture is that every widget that you use on the Haskell side has a custom destructor that cleans up callbacks into the Haskell runtime when it's deleted so the GHC GC can free the resources they close over. Because of that each user constructable widget is essentially a branch point the inheritance chain.

@mitchellwrosen
Copy link
Contributor Author

Interesting! A follow-up question, if I were to write my own Button, would I subclass like this?

WidgetBase -> Widget
 |
 v
ButtonBase -> Button
           -> MyButton

Or like this?

WidgetBase -> Widget
 |
 v
ButtonBase -> Button -> MyButton

If the former, is there any functionality in Button that I'm "leaving behind"...? (And presumably would want to re-implement in MyButton)

@deech
Copy link
Owner

deech commented Apr 23, 2019

If you want to create your own button you'd use buttonCustom which allows you to customize a small set of essential functions. Overriding arbitrary functions in the inheritance chain is not supported.

@mitchellwrosen
Copy link
Contributor Author

Got it. Another question (sorry!) - the *Base types do crop up in the API, for example in

getParent :: Ref WidgetBase -> IO (Maybe (Ref GroupBase))

you're going to get back a Ref GroupBase no matter what type you started with. Is there a reason why this isn't Ref Group - going off of an assumption that the *Base types are somewhat "internal"?

@deech
Copy link
Owner

deech commented Apr 23, 2019

Also while this is limiting you can do quite a bit with just those. The entire fltkhs-themes package relies mostly custon draw and handle to get a completely different look-and-feel.

@deech
Copy link
Owner

deech commented Apr 23, 2019

Ah yes, they do crop up in return types, you're right. You don't want a Ref Group there because it is only guaranteed to be a GroupBase (ie. Fl_Group) since the parent may not have been constructed by you but by methods on the C++ side. This is also why getChild returns Ref WidgetBase instead of widget.

@mitchellwrosen
Copy link
Contributor Author

Very helpful! Could you clarify why one might not want to immediately upcast every Foo they encounter to a BaseFoo? I'm still struggling to understand the essence of the distinction (from an API standpoint).

@mitchellwrosen
Copy link
Contributor Author

Oh - is the answer that in doing so, you'd toss out your custom overrides?

@deech
Copy link
Owner

deech commented Apr 23, 2019

Hmm.. let me think about that. You maybe right, you can't really add member functions to a child when you override so a Foo could be used safely as BaseFoo but you shouldn't need to upcast like that for normal cases. Even when passing some MyButton into another function I have a Parent constraint that does the check for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants