[Pharo-project] NativeBoost extending Object
Hi guys, Looking at NB methods extending Object I am wandering if it won't be better to put them in a Trait to be used by any class needing them? As for ByteArray maybe instead of using the methods inherited from Object maybe we can use a double-dispatch scheme to delegate NB calls to another class. This way we won't need to extend Object anymore... Igor, what do you think? (if you agree I will do it for NB)... I don't know if that will play well with existing NB-based projects though (Athens, NBOpenGL, etc...) But I think it is worth it on the long run... Cheers, -- Dr. Ciprian TEODOROV Ingénieur Développement CAO tél : 06 08 54 73 48 mail : ciprian.teodorov@gmail.com www.teodorov.ro
On 28 November 2012 22:24, Ciprian Teodorov <ciprian.teodorov@gmail.com> wrote:
Hi guys,
Looking at NB methods extending Object I am wandering if it won't be better to put them in a Trait to be used by any class needing them?
i don't see what you will gain from that, except that you will end up using that trait all over the places? Imo extension to Object is fine. All methods use namespace prefix, so there is a little chance to clash with some other project/package. What i dislike about traits that if it used multiple times, browsing implementors of trait method will give you list of all very same methods where that trait is used. So, if you not careful enough, you can mistakenly change method for a single class, instead of modifying trait method..
As for ByteArray maybe instead of using the methods inherited from Object maybe we can use a double-dispatch scheme to delegate NB calls to another class.
i see that you want to avoid duplicated code. but delegation will cost 1 more message send. while i actually wondering if we need those extensions at all. except from some important ones (internally by NB), i don't think that using nbXAtOffset: is good practice. I think that people should use more higher level abstractions for working with data. those methods providing direct access to memory (with all possible consequences).. so one should use them only if there's no better/more elegant way. So, even if you put implementation into single class, it won't make things less bloated: you will still have to provide a 'delegation methods' , i.e.: nbXXXAtOffset: offset ^ SomeGuyInCharge doXXXAtOffset: offset for: self which won't make number of methods any bit smaller. that's why i asking , what if better would be to look for a ways how we can get rid of all of them instead.. and provide something better in exchange.
This way we won't need to extend Object anymore...
Igor, what do you think?
well, extensions were put for reason: to avoid using globals and to make things more convenient to use. don't let me wrong: i don't like extending Object.. especially over-extending: right now it is 9 extension methods. I'd rather consider if we can shrink that protocol to remove: nbCall: fnSpec module: aModuleNameOrHandle options: callOptions nbCall: fnSpec options: callOptions nbCall: fnSpec module: aModuleNameOrHandle nbCall: fnSpec since new api, which i introduced recently, provides similar abilities without need of polluting any class(es) protocols more than necessary.
(if you agree I will do it for NB)... I don't know if that will play well with existing NB-based projects though (Athens, NBOpenGL, etc...) But I think it is worth it on the long run...
Cheers, -- Dr. Ciprian TEODOROV Ingénieur Développement CAO
tél : 06 08 54 73 48 mail : ciprian.teodorov@gmail.com www.teodorov.ro
-- Best regards, Igor Stasenko.
Hi Igor, While I can clearly see your points, I don't quite agree with all of them, probably because I don't have as much experience as you do. See bellow some of my thoughts on the matter. At the end I like very much NativeBoost today, and I think discussing these things helps us move forward and assume the choices that are made. On Wed, Nov 28, 2012 at 11:04 PM, Igor Stasenko <siguctua@gmail.com> wrote:
On 28 November 2012 22:24, Ciprian Teodorov <ciprian.teodorov@gmail.com> wrote:
Hi guys,
Looking at NB methods extending Object I am wandering if it won't be better to put them in a Trait to be used by any class needing them?
i don't see what you will gain from that, except that you will end up using that trait all over the places?
What do you understand about all over the places? In my opinion FFI calls should be very well isolated in specific modules that are meant for that. I think we might have different views on this issue... I see using external libraries as a limited number of classes (maybe just one in most cases) doing the native calls, and then writing a library that relies on these classes only for calling the external library. This way the external interfaces are well defined, and we don't run the risk of having the whole image full of FFI calls...
Imo extension to Object is fine. All methods use namespace prefix, so there is a little chance to clash with some other project/package.
yes I agree namespace prefix protects us somehow (at the same time I'm looking the whole day at C code with company_library_MyFoo(x, y, z) calls and I don't like it)
What i dislike about traits that if it used multiple times,
browsing implementors of trait method will give you list of all very same methods where that trait is used. So, if you not careful enough, you can mistakenly change method for a single class, instead of modifying trait method..
This sucks, but I think that it is not an issue, maybe someday the traits will get the attention they deserve, and somebody will fix this problem. I'm a dreamer maybe... but well
As for ByteArray maybe instead of using the methods inherited from Object maybe we can use a double-dispatch scheme to delegate NB calls to another class.
i see that you want to avoid duplicated code. but delegation will cost 1 more message send. while i actually wondering if we need those extensions at all. except from some important ones (internally by NB), i don't think that using nbXAtOffset: is good practice. I think that people should use more higher level abstractions for working with data. those methods providing direct access to memory (with all possible consequences).. so one should use them only if there's no better/more elegant way.
So, even if you put implementation into single class, it won't make things less bloated: you will still have to provide a 'delegation methods' , i.e.:
nbXXXAtOffset: offset ^ SomeGuyInCharge doXXXAtOffset: offset for: self
which won't make number of methods any bit smaller. that's why i asking , what if better would be to look for a ways how we can get rid of all of them instead.. and provide something better in exchange.
I completely agree with you on this...
This way we won't need to extend Object anymore...
Igor, what do you think?
well, extensions were put for reason: to avoid using globals and to make things more convenient to use.
don't let me wrong: i don't like extending Object.. especially over-extending: right now it is 9 extension methods. I'd rather consider if we can shrink that protocol to remove: nbCall: fnSpec module: aModuleNameOrHandle options: callOptions nbCall: fnSpec options: callOptions nbCall: fnSpec module: aModuleNameOrHandle nbCall: fnSpec
since new api, which i introduced recently, provides similar abilities without need of polluting any class(es) protocols more than necessary.
Yep your new API is cool I like it...
I hope I'm not bothering you too much with these small things... By the way did you see my last mail about structs, and enums...? good night
(if you agree I will do it for NB)... I don't know if that will play well with existing NB-based projects though (Athens, NBOpenGL, etc...) But I think it is worth it on the long run...
Cheers, -- Dr. Ciprian TEODOROV Ingénieur Développement CAO
tél : 06 08 54 73 48 mail : ciprian.teodorov@gmail.com www.teodorov.ro
-- Best regards, Igor Stasenko.
-- Dr. Ciprian TEODOROV Ingénieur Développement CAO tél : 06 08 54 73 48 mail : ciprian.teodorov@gmail.com www.teodorov.ro
On 28 November 2012 22:24, Ciprian Teodorov <ciprian.teodorov@gmail.com> wrote:
Hi guys,
Looking at NB methods extending Object I am wandering if it won't be better to put them in a Trait to be used by any class needing them?
i don't see what you will gain from that, except that you will end up using that trait all over the places?
What do you understand about all over the places? In my opinion FFI calls should be very well isolated in specific modules that are meant for that. I think we might have different views on this issue... I see using external libraries as a limited number of classes (maybe just one in most cases) doing the native calls, and then writing a library that relies on these classes only for calling the external library. This way the external interfaces are well defined, and we don't run the risk of having the whole image full of FFI calls...
I think so too, traits would help limiting the scope of FFI. maybe the tools could require some polish, but not using traits won't help ;)
On 29 November 2012 00:58, Camillo Bruni <camillobruni@gmail.com> wrote:
On 28 November 2012 22:24, Ciprian Teodorov <ciprian.teodorov@gmail.com> wrote:
Hi guys,
Looking at NB methods extending Object I am wandering if it won't be better to put them in a Trait to be used by any class needing them?
i don't see what you will gain from that, except that you will end up using that trait all over the places?
What do you understand about all over the places? In my opinion FFI calls should be very well isolated in specific modules that are meant for that. I think we might have different views on this issue... I see using external libraries as a limited number of classes (maybe just one in most cases) doing the native calls, and then writing a library that relies on these classes only for calling the external library. This way the external interfaces are well defined, and we don't run the risk of having the whole image full of FFI calls...
I think so too, traits would help limiting the scope of FFI.
maybe the tools could require some polish, but not using traits won't help ;)
every time one using double negation, a small kitten dies. so, please clarify your statement :) -- Best regards, Igor Stasenko.
I think so too, traits would help limiting the scope of FFI.
maybe the tools could require some polish, but not using traits won't help ;)
every time one using double negation, a small kitten dies.
so, please clarify your statement :)
the double negation stays: not using traits won't help <=> using traits will help ... improving the infrastructure
On 29 November 2012 02:42, Camillo Bruni <camillobruni@gmail.com> wrote:
I think so too, traits would help limiting the scope of FFI.
maybe the tools could require some polish, but not using traits won't help ;)
every time one using double negation, a small kitten dies.
so, please clarify your statement :)
the double negation stays:
not using traits won't help <=> using traits will help
... improving the infrastructure
my main problem with traits that number of compiled methods in system is going to be n*m, where n is number of methods in trait and m is number of root-classes where it used. and i am not really happy with that. I prefer having 9 methods in Object than 9*100 methods in many classes. while it is fine from developer's POV (because tools can hide this), you still paying the price. just to make sure guys, you know about this, maybe it will lower your obsession with traits :) -- Best regards, Igor Stasenko.
my main problem with traits that number of compiled methods in system is going to be n*m, where n is number of methods in trait and m is number of root-classes where it used.
so? if that is your concern, then you chose the wrong progamming language...
and i am not really happy with that. I prefer having 9 methods in Object than 9*100 methods in many classes.
that's just because traits are a "hack" and copy down methods to make it work, but you as user won't care.
while it is fine from developer's POV (because tools can hide this), you still paying the price.
where? memory is the only thing you may waste, and we still have plenty of it to waste.
just to make sure guys, you know about this, maybe it will lower your obsession with traits :)
I think all your doubts are based on wrong ideas. Maybe if you come from C++ or C yes, but we're in Smalltalk? Modularity and maintainability is what you want to go for! size of objects in memory, specially static objects like methods, is a thing you hardly ever care about...
On 28/11/12 9:32 PM, Camillo Bruni wrote:
where? memory is the only thing you may waste, and we still have plenty of it to waste.
That's the kind of thinking that can lead to things like needing 100's of MB of RAM just to run the Java-based install programs. IMHO, conserving resources is always important, and some times has to be traded-off.
just to make sure guys, you know about this, maybe it will lower your obsession with traits :)
I think all your doubts are based on wrong ideas. Maybe if you come from C++ or C yes, but we're in Smalltalk? Modularity and maintainability is what you want to go for! size of objects in memory, specially static objects like methods, is a thing you hardly ever care about...
You said "hardly ever care", but when you care - it matters. I'd like to be able to run many images on a single server. If you make each base image big, then I can run fewer such images. If it's in the base image, and it's not striped out by #prepareForProduction, then it's a problem.
I remember reading about some issues with sharing traits code, however I don't remember exactly the problem. But it seemed that it can be fixed... Can somebody refresh my memory on that? If it is only an implementation problem maybe we can fix it... In that case the n*m issue is gone. About using 'self' in nb calls I don't see any problem, it just means that your class uses the trait, and it is doing ffi... On Nov 29, 2012 7:00 AM, "Yanni Chiu" <yanni@rogers.com> wrote:
On 28/11/12 9:32 PM, Camillo Bruni wrote:
where? memory is the only thing you may waste, and we still have plenty of it to waste.
That's the kind of thinking that can lead to things like needing 100's of MB of RAM just to run the Java-based install programs. IMHO, conserving resources is always important, and some times has to be traded-off.
just to make sure guys, you know about this, maybe it will lower your
obsession with traits :)
I think all your doubts are based on wrong ideas. Maybe if you come from C++ or C yes, but we're in Smalltalk? Modularity and maintainability is what you want to go for! size of objects in memory, specially static objects like methods, is a thing you hardly ever care about...
You said "hardly ever care", but when you care - it matters. I'd like to be able to run many images on a single server. If you make each base image big, then I can run fewer such images. If it's in the base image, and it's not striped out by #prepareForProduction, then it's a problem.
On 29 November 2012 00:38, Ciprian Teodorov <ciprian.teodorov@gmail.com> wrote:
Hi Igor,
While I can clearly see your points, I don't quite agree with all of them, probably because I don't have as much experience as you do. See bellow some of my thoughts on the matter. At the end I like very much NativeBoost today, and I think discussing these things helps us move forward and assume the choices that are made.
On Wed, Nov 28, 2012 at 11:04 PM, Igor Stasenko <siguctua@gmail.com> wrote:
On 28 November 2012 22:24, Ciprian Teodorov <ciprian.teodorov@gmail.com> wrote:
Hi guys,
Looking at NB methods extending Object I am wandering if it won't be better to put them in a Trait to be used by any class needing them?
i don't see what you will gain from that, except that you will end up using that trait all over the places?
What do you understand about all over the places? In my opinion FFI calls should be very well isolated in specific modules that are meant for that. I think we might have different views on this issue... I see using external libraries as a limited number of classes (maybe just one in most cases) doing the native calls, and then writing a library that relies on these classes only for calling the external library. This way the external interfaces are well defined, and we don't run the risk of having the whole image full of FFI calls...
In Athens Cairo backend we're using trait TCairoLibrary, which implements single method: #nbLibraryNameOrHandle and still its implementation delegates things to concrete class: nbLibraryNameOrHandle ^ CairoLibraryLoader getLibraryHandle Now there's like 10 or more classes which using this trait. If i put all FFI calls into single class then a) i will not need trait anymore b) i will not need a NB trait as well, because i could just implement own convenience methods in that class and its over but once i will do that, i will produce a god-class which will know everything about cairo and its interfaces. more than that, a certain and convenient uses of FFI callouts will be no longer possible: AthensCairoCanvas>>setSourceR: red g: green b: blue a: alpha <primitive: #primitiveNativeCall module: #NativeBoostPlugin> ^ self nbCall: #( void cairo_set_source_rgba ( self , double red, double green, double blue, double alpha) ) instead you will be forced to write it like: AthensCairoCanvas>>setSourceR: red g: green b: blue a: alpha ^ CairoCentral canvas: self setSourceR: red g: green b: blue a: alpha so, instead of single method, which implements given interface (and often it is just enough), you'll have to implement it in central and then in delegate classes. Which basically means doubling number of methods per single FFI call. More code -> more time -> more effort to maintain (and a lot of other 'more's )... second , you cannot use 'self' in function signature, and instead you will be forced to use AthensCairoCanvas * canvas (or similar).. which implies type-check in generated code while for 'self' its not, because if method belongs to certain class it is guaranteed that receiver is always of same type , so you can avoid type check. There's of course many other reasons why i do not like putting everything into single basket: - classes with 100000 methods just stinking badly. Because you can no longer reason & quickly decide whether you need all 100000 or can live with 99999 of them or maybe even 99998. So, i just shown what lies on surface: sure you can isolate all FFI callouts into single module/class.. but separating concerns is much more helpful for development and maintaining code. that's why i love using smalltalk and browser to code instead of C and text editor with single file which holds multi-million lines of source code. -- Best regards, Igor Stasenko.
What i dislike about traits that if it used multiple times, browsing implementors of trait method will give you list of all very same methods where that trait is used. So, if you not careful enough, you can mistakenly change method for a single class, instead of modifying trait method..
nope this does no longer happen in 2.0, I change implementors/senders to only show the method definitions. So trait methods are only shown on traits. aka, random changes don't happen that easily anymore
participants (4)
-
Camillo Bruni -
Ciprian Teodorov -
Igor Stasenko -
Yanni Chiu