Hello everybody, The question I have concerns OSWindow and its backend : SDL. However, even if I'll speak about these two, i think the question is quite general and can apply to every API.In this case I see two options : |
A recent idea I had, translated to your case, was doing this by providing accessors to specific backend extension classes. Personally, I'd prefer to use a class separate from that which implements the common interface, so one doesn't accidentally end up doing common calls on only specific backends, here's a purely theoretical example of how that may look: window := OSWindow new. window title: 'Test window'. "With SDL, we support making window unbordered" window SDL bordered: false. window openInWorld. With a few example implementations: OSWindow >> #SDL "Could cache in instvar, but that would not as modular, as you can't package that with the rest of the backend, with methods all you need is *SDL-Windows categorization" currentBackEnd isSDL ifTrue: [SDL_ExtWindow target: self] ifFalse: [NoopWindow target: self] SDLExtendedWindow >> #bordered: aBoolean <primitive: #primitiveNativeCall module: #NativeBoostPlugin error: errorCode> ^ self nbCall: #( int SDL_SetWindowBordered ( SDL_Window * target , SDL_bool aBoolean ) ) Haven't actually used this pattern yet, but at least to me, it yields a clear distinction between what is common between backends, and what will only work on some. SDL is of course a somewhat special case, at it itself is an abstraction over different backends, and there's little functionality there that could not be part of a standard window API... Cheers, Henry
|
Thank you for your answer, as you said, this pattern makes things quite clear for the user. I like it :) SDL is of course a somewhat special case, at it itself is an abstraction over different backends, and there's little functionality there that could not be part of a standard window API... Yeah, that's true. But actually SDL is not even really a GUI / Windowing API. As stated ont heir website it is "[...]designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware [...]" So I guess it's the other way arround. You can probably do things with a real window API that you cannot do with SDL. What made me think of this "issue" is a new functionnality coming with the next version of SDL2 : https://wiki.libsdl.org/SDL_SetWindowHitTest I implemented this in OSWindow and then I asked myself if all the other libraries could do the same. I mean, it is always possible to move a window without decorations by using the mouse position and calls to "set window position" or whatever. Same goes for resizing. But the SDL way is so easy and painless that I wanted to know if the exact same way was doable with other libraries. After some basic researches on GTK+ I was not really able to tell if it was possible to do so. So a new question arose : Should I really look at every possible backend to know if a functionnality is general or backend-specific ? :/ 2015-06-16 12:15 GMT+02:00 Henrik Johansen <[hidden email]>:
|
In reply to this post by Henrik Sperre Johansen
On Tue, Jun 16, 2015 at 6:15 PM, Henrik Johansen
<[hidden email]> wrote: > > On 16 Jun 2015, at 9:58 , Matthieu Lacaton <[hidden email]> > wrote: > > Hello everybody, > > The question I have concerns OSWindow and its backend : SDL. However, even > if I'll speak about these two, i think the question is quite general and can > apply to every API. > > There are some functions that we are sure we will find in every backend > possible (for instance the possibility to create a new window, to resize it > etc.) and for these ones it is totally fine to abstract the backend from the > user because you know that even if the backend has to change the API will be > usable the same way. > > But there are some functions that are quite specific to a certain backend > and you cannot always find it in others. But this function is cool so it > would be a shame not to implement it just for the sake of uniformity. > In this case I see two options : > > 1) You abstract these functions exactly the same way you did for the others > and the user is not informed at all. In this case the risk is that if the > backend changes it may break the API for the user because he won't be able > to use this function anymore.And he may feel a bit sad because he was not > warned about it. > > 2) You make something to let the user know that this or that function is > specific to this or that backend. By doing so the user knows that there is a > small risk that he won't be able to use this function anymore if the backend > changes. He has been warned. > > Now I prefer the second option but I wanted to ask you about that > "something". What is the best way to warn the user ? > > - Should I let the name of the backend in the name of the method ? > "SDL_MySpecificMethod" > - Should I put all these methods in a specific package and name / comment > that package accordingly ? > - Some other things ? > > Basically my question is : what is the best way to let the user know he is > dealing with a specific function for a specific backend ? > > Thanks, > > Matthieu > > > A recent idea I had, translated to your case, was doing this by providing > accessors to specific backend extension classes. > Personally, I'd prefer to use a class separate from that which implements > the common interface, so one doesn't accidentally end up doing common calls > on only specific backends, here's a purely theoretical example of how that > may look: > > window := OSWindow new. > window title: 'Test window'. > "With SDL, we support making window unbordered" > window SDL bordered: false. > window openInWorld. But what would this code look like when later a second backend XDL does implement #bordered: ? > With a few example implementations: > OSWindow >> #SDL > "Could cache in instvar, but that would not as modular, as you can't > package that with the rest of the backend, with methods all you need > is *SDL-Windows categorization" > currentBackEnd isSDL > ifTrue: [SDL_ExtWindow target: self] > ifFalse: [NoopWindow target: self] I don't see /currentBackEnd/ is current OSWindow. I presume you are adding it. What class would you store in /currentBackEnd/ ? I guess some would have a philosophical object to "isSDL ifTrue:ifFalse: pattern. NoopWindow subclass: SDL_ExtWindow. NoopWindow subclass: XDL_ExtWindow. NoopWindow>>bordered: somewhere "currentBackEnd := SDL_ExtWindow new." > SDLExtendedWindow >> #bordered: aBoolean > <primitive: #primitiveNativeCall module: #NativeBoostPlugin error: > errorCode> > ^ self nbCall: #( int SDL_SetWindowBordered ( SDL_Window * target , SDL_bool > aBoolean ) ) > > Haven't actually used this pattern yet, but at least to me, it yields a > clear distinction between what is common between backends, and what will > only work on some. > SDL is of course a somewhat special case, at it itself is an abstraction > over different backends, and there's little functionality there that could > not be part of a standard window API... > > Cheers, > Henry |
I think the example of Henrik works fine if the user knows precisely what he wants to do. If I understand what Ben said, the following should also be possible : Create x subclasses of OSWindow (x being the number of backends available). For example : OSWindow subclass: OSWindowSDL OSWindow subclass: OSWindowXDL Now, at the initialization of OSWindow the corresponding subclass is stored into the currentBackend instance variable (a bit like in a strategy pattern). So either currentBackend := OSWindowSDL new or currentBackend := OSWindowXDL new. If the method called is backend-specific the implementation could be done like that : OSWindow >> #bordered: aBoolean ^ currentBackend bordered: aBoolean for: self OSWindowSDL >> #bordered: aBoolean for: target <primitive: #primitiveNativeCall module: #NativeBoostPlugin error: errorCode> ^ self nbCall: #( int SDL_SetWindowBordered ( SDL_Window *target , SDL_bool aBoolean ) ) OSWindowXDL >> #bordered: aBoolean for: target ^ self error: 'Warning, the current backend does not provide support for #bordered, you should use another one'. And maybe provide a list of available backends providing this option. And the user just needs to call OSWindow bordered: false. The drawback here is that there is no real distinction between common and specific backend for the user. He only knows when it bugs. The advantage is that the user can use specific functions without even knowing it :D 2015-06-16 14:30 GMT+02:00 Ben Coman <[hidden email]>:
|
In reply to this post by Henrik Sperre Johansen
I like this idea too because it makes clear that you are using an
back-end specific behavior.
Le 16/6/15 12:15, Henrik Johansen a
écrit :
|
Free forum by Nabble | Edit this page |