Empirical Analysis of Programming Language Adoption
I bumped into a paper "Empirical Analysis of Programming Language Adoption" that I thought might be of interest to others since we'd like to increase Pharo's mindshare. (http://sns.cs.princeton.edu/docs/asr-oopsla13.pdf) TLDR; my top three take outs were... Figure 5 indicates that simple syntax and languages features don't attract new users, and of the things we can control the most important are... performance, portability and development speed. Figure 12 suggests a strategy to promote useful libraries rather than language features. I guess that might best take take the form blogs showing the use of libraries. Table 7 makes and interesting assertion that static types are more important for readability than preventing bugs. cheers -ben P.S. Then I bumped into "Toward Semantic Foundations for Program Editors" (https://arxiv.org/pdf/1703.08694.pdf) which was over my head but I guess it might be interesting to people working in UI area.
Ben Coman wrote
the most important are... performance, portability and development speed.
I wonder about this because Ruby and Python are no speed demons and it's hard to imagine anyone (except maybe lisp) beating Smalltalk in development speed. I didn't read the article, but it seems to me the main factor in popularity is random chance because the industry is a pop culture where trends are more about being cool (or getting a job) than any underlying principles. Coding "academies" seem to be the latest caricature of this phenomenon: "Want to code? For just $1,995 we'll will get you job ready w the sexiest languages in just 3 weeks! And that's not all⦠we'll even throw in this ironic hipster coding T-shirt for free!!" That said, IMHO mainstream popularity is a curse. The sweet spot is a critical mass where the core and desired libraries are available and maintained. ----- Cheers, Sean -- Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html
On 8 June 2018 at 20:49, Sean P. DeNigris <sean@clipperadams.com> wrote:
Ben Coman wrote
the most important are... performance, portability and development speed.
I wonder about this because Ruby and Python are no speed demons and it's hard to imagine anyone (except maybe lisp) beating Smalltalk in development speed.
So its not all three at once, but different choices for different domains. And maybe Smalltalk is trumped by the next two most important... Personal familiarity (E) Team familiarity (E) where such "familiarity" encompasses text-based versus image-based systems. And we can't do much about these... Extending existing code (E) Already used in group (E) So we just promote what we can influene.
I didn't read the article, but it seems to me the main factor in popularity is random chance because the industry is a pop culture where trends are more about being cool (or getting a job) than any underlying principles.
And this reinforces "Personal familiarity" and perhaps a bit like Coca Cola adverts. Their aim is not to make you rush from the TV to go and get a Coke, but just the next time you are standing in the corner store deciding which you might choose, its Coke that comes to mind. That said, IMHO mainstream popularity is a curse. The sweet spot is a
critical mass where the core and desired libraries are available and maintained.
Agreed. cheers -ben
Hi Ben, Interesting find. 2018-06-08 14:29 GMT+02:00 Ben Coman <btc@openinworld.com>:
I bumped into a paper "Empirical Analysis of Programming Language Adoption" that I thought might be of interest to others since we'd like to increase Pharo's mindshare. (http://sns.cs.princeton.edu/docs/asr-oopsla13.pdf)
TLDR; my top three take outs were...
Figure 5 indicates that simple syntax and languages features don't attract new users, and of the things we can control the most important are... performance, portability and development speed.
This is interesting, and they also insist in the paper that developpers do not care that much about the semantics of what they use...
Figure 12 suggests a strategy to promote useful libraries rather than language features. I guess that might best take take the form blogs showing the use of libraries.
And have librairies that are really usefull... A possible strategy then would be a stable, clean core, and librairies that really make a difference.
Table 7 makes and interesting assertion that static types are more important for readability than preventing bugs.
This one is in line with Dan Luu meta-study that static typing catches at best a small proportion of bugs. Note that this is used in Smalltalk, when you write anInteger, aString : you're using a form of typing for documentation. By the way, I wrote for fun a small metalink-based run-time type-checker using method argument names. To be used when running unit tests :) Regards, Thierry
cheers -ben
P.S. Then I bumped into "Toward Semantic Foundations for Program Editors" (https://arxiv.org/pdf/1703.08694.pdf) which was over my head but I guess it might be interesting to people working in UI area.
Thierry Goubier wrote
By the way, I wrote for fun a small metalink-based run-time type-checker using method argument names. To be used when running unit tests :)
Cool! Is that public? ----- Cheers, Sean -- Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html
2018-06-08 14:54 GMT+02:00 Sean P. DeNigris <sean@clipperadams.com>:
Thierry Goubier wrote
By the way, I wrote for fun a small metalink-based run-time type-checker using method argument names. To be used when running unit tests :)
Cool! Is that public?
Yes. It's at: https://github.com/ThierryGoubier/AltBrowser/tree/pharo6/Alt-TypeCheck.packa... It decodes things like anArrayOf, anIntOrString and similar names, and writes a metalink-based type check. Thierry
----- Cheers, Sean -- Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html
2018-06-08 14:50 GMT+02:00 Thierry Goubier <thierry.goubier@gmail.com>:
Hi Ben,
Interesting find.
... snip ...
Table 7 makes and interesting assertion that static types are more important for readability than preventing bugs.
This one is in line with Dan Luu meta-study that static typing catches at best a small proportion of bugs.
Note that this is used in Smalltalk, when you write anInteger, aString : you're using a form of typing for documentation.
Exactly!
And if you transpose this style to static typing you get things like Cat *theCat = new Cat; Being tainted, I always thought that is was noise... You'd better rename your variable felix;) Static typing may help the IDE (refactoring and navigating). My POV is thus that you enter this information for the tools, not for the humans (compiler, navigator, refactoring engine, ...). I have differently tainted colleagues still thinking that the type help them reading code... So, IMO, this assertion reflects the dominant culture rather than intrinsic merits. IOW, if you want to create a successfull language, just clone an existing one :( Nicolas By the way, I wrote for fun a small metalink-based run-time
type-checker using method argument names. To be used when running unit tests :)
Regards,
Thierry
2018-06-08 16:35 GMT+02:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
2018-06-08 14:50 GMT+02:00 Thierry Goubier <thierry.goubier@gmail.com>:
Hi Ben,
Interesting find.
... snip ...
Table 7 makes and interesting assertion that static types are more important for readability than preventing bugs.
This one is in line with Dan Luu meta-study that static typing catches at best a small proportion of bugs.
Note that this is used in Smalltalk, when you write anInteger, aString : you're using a form of typing for documentation.
Exactly!
And if you transpose this style to static typing you get things like Cat *theCat = new Cat; Being tainted, I always thought that is was noise... You'd better rename your variable felix;)
This is a good example of noise :) What my concern would be is that advances in AI, like the Bayou completion system, clearly shows that this is noise and that it can be inferred.
Static typing may help the IDE (refactoring and navigating). My POV is thus that you enter this information for the tools, not for the humans (compiler, navigator, refactoring engine, ...).
I used to believe that, and then I switched to a slightly different view, thanks to some use of the OCaml type inference. In some cases, when you design systems for reuse (for example libraries), you understand that you're building code generic enough to accept a lot more than the types you intent to allow (and even static type inference manages to infer that fact for you). So, to ease reuse and maintenance of your code, typing the API (either by naming convention or by restricting types in OCaml) can be a good solution. Now, the real need for types is when you want to do high performance compilation, because compilers are pretty bad at type inference (and need very precise and limited types to produce efficient code).
I have differently tainted colleagues still thinking that the type help them reading code... So, IMO, this assertion reflects the dominant culture rather than intrinsic merits.
I still think that whatever name you use for your variables, you often convey an idea of a type with your naming choices (i.e. felix is probably a cat, probably not a dialog box....)
IOW, if you want to create a successfull language, just clone an existing one :(
Thierry
Nicolas
By the way, I wrote for fun a small metalink-based run-time type-checker using method argument names. To be used when running unit tests :)
Regards,
Thierry
2018-06-08 17:05 GMT+02:00 Thierry Goubier <thierry.goubier@gmail.com>:
2018-06-08 16:35 GMT+02:00 Nicolas Cellier <nicolas.cellier.aka.nice@ gmail.com>:
2018-06-08 14:50 GMT+02:00 Thierry Goubier <thierry.goubier@gmail.com>:
Hi Ben,
Interesting find.
... snip ...
Table 7 makes and interesting assertion that static types are more important for readability than preventing bugs.
This one is in line with Dan Luu meta-study that static typing catches at best a small proportion of bugs.
Note that this is used in Smalltalk, when you write anInteger, aString : you're using a form of typing for documentation.
Exactly!
And if you transpose this style to static typing you get things like Cat *theCat = new Cat; Being tainted, I always thought that is was noise... You'd better rename your variable felix;)
This is a good example of noise :)
What my concern would be is that advances in AI, like the Bayou completion system, clearly shows that this is noise and that it can be inferred.
Static typing may help the IDE (refactoring and navigating). My POV is thus that you enter this information for the tools, not for the humans (compiler, navigator, refactoring engine, ...).
I used to believe that, and then I switched to a slightly different view, thanks to some use of the OCaml type inference. In some cases, when you design systems for reuse (for example libraries), you understand that you're building code generic enough to accept a lot more than the types you intent to allow (and even static type inference manages to infer that fact for you). So, to ease reuse and maintenance of your code, typing the API (either by naming convention or by restricting types in OCaml) can be a good solution.
Now, the real need for types is when you want to do high performance compilation, because compilers are pretty bad at type inference (and need very precise and limited types to produce efficient code).
Yes, I don't know these languages enough, but it's indeed an extensible specification of types (as expectations). And this have values both for tools (compiling/browsing/static checks) and humans. Oh, and if it helps browser, then it helps humans, because browser is for humans.
Our Smalltalk way would be to use many small Traits specifying the API and have optional type hints using those Traits (wasn't it a Strongtalk experiment?) But note that such static analysis imposes more limits on code than necessary: If I have some method like this: myMethod myInstVar doSomething Then a naive static inferencer will deduce that myInstVar can't be an instance of MyPartlyPolymorphicClass because it does not responds to doSomething . However, it's a lot more involved to analyze whether myMethod is ever reached... For example, if myMethod send was protected with a guard clause or exception handling... mainMethod myInstVar likesToDoSomething ifFalse: [^self]. myInstVar doSomething anotherMethodSendingDoSomething [myInstVar doSomething] onError: [IncorrectInput raise] IOW, since myMethod is not private, I can't guaranty that the library is correct. But a more clever analyzer could guaranty that a certain usage of that library is. Even in OCaml or Haskell, I'm not sure whether the type inference would be powerful enough... OK, maybe such liberality is not a good feature in the long term i.e. necessitates implicit knowledge of crooked implicit pre-conditions that message arguments must meet, or render the understanding of code difficult, thus the testing, the review and the modification worse, etc... But it might be very useful for short term experiments. Allowing partially correct programs/libraries is an important feature for the exploring phase.
I have differently tainted colleagues still thinking that the type help them
reading code... So, IMO, this assertion reflects the dominant culture rather than intrinsic merits.
I still think that whatever name you use for your variables, you often convey an idea of a type with your naming choices (i.e. felix is probably a cat, probably not a dialog box....)
Agree, type and semantics have some coverage, but as I wrote in answer to Thomas, such inference requires prior knowledge.
I once had a colleague choosing completely arbitrary names for temporaries (like the first name of his children). Whatever the presence of type declaration (C++), this was really disturbing! Bad names are bad names, and the type declaration does not help that much in such case. Nicolas
Thierry
Nicolas
Le 08/06/2018 à 19:43, Nicolas Cellier a écrit :
...
Yes, I don't know these languages enough, but it's indeed an extensible specification of types (as expectations). And this have values both for tools (compiling/browsing/static checks) and humans. Oh, and if it helps browser, then it helps humans, because browser is for humans.
Yes. And the browser is a very limited view of what is currently underway...
Our Smalltalk way would be to use many small Traits specifying the API and have optional type hints using those Traits (wasn't it a Strongtalk experiment?)
Not sure. My view at the moment is that we have three ways to reach that point: expressing intent, or guessing it (or learning it). I think most code already contain enough information for the last two to work reasonably well, and approaches that forces you to add optional type hints (another level of information, that is) are rooted in the past.
But note that such static analysis imposes more limits on code than necessary: If I have some method like this: myMethod  myInstVar doSomething
Then a naive static inferencer will deduce that myInstVar can't be an instance of MyPartlyPolymorphicClass because it does not responds to doSomething .
Yes. This is a first concern with types: they rejects incomplete programs (this is a point discussed in the paper Ben linked).
However, it's a lot more involved to analyze whether myMethod is ever reached... For example, if myMethod send was protected with a guard clause or exception handling...
mainMethod    myInstVar likesToDoSomething ifFalse: [^self].    myInstVar doSomething
anotherMethodSendingDoSomething    [myInstVar doSomething] onError: [IncorrectInput raise]
IOW, since myMethod is not private, I can't guaranty that the library is correct. But a more clever analyzer could guaranty that a certain usage of that library is.
Even in OCaml or Haskell, I'm not sure whether the type inference would be powerful enough...
Well, using it shows you it is rather impressive... Looking at 'myInstVar doSomething' it nicely express it as any class which answer to doSomething ... And that was the point where I restarted using Smalltalk instead ;) If a static thing with all its complexity (composite types, inheritence, modules, etc...) is just giving you the same duck typing as Smalltalk does, why do I have to put up with all the additional complexity for a so small gain? In the time of a short introductory course to OCaml, you understand that you are spending a lot of time dealing with types, unnecessary dealing with them, fighting with them, fighting with the type inference limitations, fighting with the confusing error messages, and that just to write smalltalk-like code in a smalltalk-like vm (in a less elegant syntax, to boot).
OK, maybe such liberality is not a good feature in the long term i.e. necessitates implicit knowledge of crooked implicit pre-conditions that message arguments must meet, or render the understanding of code difficult, thus the testing, the review and the modification worse, etc...
I think a good system would probably learn from source code analysis and code traces (unit tests execution) to build a complete type model. I think machine learning is nowadays good enough to do that. Remember that you don't need it to be "proven sound", just good enough to help you. Remember that static type checking catches about 5% of the bugs, and probably just easy ones. And that an approximate type checker would probably catch them as well...
But it might be very useful for short term experiments. Allowing partially correct programs/libraries is an important feature for the exploring phase.
Essential. Thats the power of dynamic langages and environment I'd even state that as a rule: - If you evolve a static type to a language, someone will create a dynamic typed equivalent of that langage (and a community will use it). With a corollary: - since the PL community is only doing static typing, the dynamic typed equivalent will be badly implemented by applying none of the PL research that could help.
> I have differently tainted colleagues still thinking that the type help them > reading code... > So, IMO, this assertion reflects the dominant culture rather than intrinsic > merits.
I still think that whatever name you use for your variables, you often convey an idea of a type with your naming choices (i.e. felix is probably a cat, probably not a dialog box....)
Agree, type and semantics have some coverage, but as I wrote in answer to Thomas, such inference requires prior knowledge.
Yes. Or better inference.
I once had a colleague choosing completely arbitrary names for temporaries (like the first name of his children). Whatever the presence of type declaration (C++), this was really disturbing! Bad names are bad names, and the type declaration does not help that much in such case.
Agreed. I'm sure someone or a tool can correctly type-guess out of my usual set of variable names... i is allways an int in my code :) Thierry
Nicolas
Thierry
> Nicolas >
Hello, I wanted to just write a quick comment, but it turned into an essay, sorry. ^^ Le 08/06/2018 à 16:35, Nicolas Cellier a écrit : > > > 2018-06-08 14:50 GMT+02:00 Thierry Goubier <thierry.goubier@gmail.com > <mailto:thierry.goubier@gmail.com>>: > > > Note that this is used in Smalltalk, when you write anInteger, aString > : you're using a form of typing for documentation. > > Exactly! > > And if you transpose this style to static typing you get things like >    Cat *theCat = new Cat; > Being tainted, I always thought that is was noise... > You'd better rename your variable felix;) Naming variables/arguments according to their type is only half a solution I think. Because there are actually two things I would like to know about a variable/argument when reading code: its type and its meaning. For example, knowing that an argument named "anInt" is an integer is nice, but I would also like to know that it's the number of dice the method has to roll. The two information are very useful to quickly understand the code. From what I've seen in Pharo, variables are usually named after their meaning, while method argument are named after their type, but in an ideal world I would like to know both the type and the meaning of both the variables and the arguments. That's in my opinion one of the advantages of explicit types for reading code: you write the type besides the variable/argument, so the name of the variable/argument can describe its meaning and I have both informations. > Static typing may help the IDE (refactoring and navigating). > My POV is thus that you enter this information for the tools, not for > the humans (compiler, navigator, refactoring engine, ...). > > I have differently tainted colleagues still thinking that the type > help them reading code... > So, IMO, this assertion reflects the dominant culture rather than > intrinsic merits. > IOW, if you want to create a successfull language, just clone an > existing one :( I would agree with your colleagues. I got stuck countless times when reading pharo code, because there was a message send to a variable I didn't know the type of, so I couldn't know which method was being called (because there were multiple methods with that name in the system). So the only solution was to place a breakpoint and get that method to be executed. This is not so easy (at least for me) in programs that are not really simple, because: 1) I need to have this method executed in its "normal use environment". I can't just execute it with dummy values as argument, because that will affect the values the variables will take. 2) I can look into tests, but since I don't know the program, I have no idea which tests to run to execute the piece of code. So in general, it's either asking someone that knows how the program work, or spending a lot of (annoying) time figuring out how the entire program flows values to get the type of that one variable. Thomas
2018-06-08 17:06 GMT+02:00 Thomas Dupriez < thomas.dupriez@ens-paris-saclay.fr>:
Hello, I wanted to just write a quick comment, but it turned into an essay, sorry. ^^
Le 08/06/2018 à 16:35, Nicolas Cellier a écrit :
2018-06-08 14:50 GMT+02:00 Thierry Goubier <thierry.goubier@gmail.com>:
Note that this is used in Smalltalk, when you write anInteger, aString : you're using a form of typing for documentation.
Exactly!
And if you transpose this style to static typing you get things like Cat *theCat = new Cat; Being tainted, I always thought that is was noise... You'd better rename your variable felix;)
Naming variables/arguments according to their type is only half a solution I think. Because there are actually two things I would like to know about a variable/argument when reading code: its type and its meaning. For example, knowing that an argument named "anInt" is an integer is nice, but I would also like to know that it's the number of dice the method has to roll. The two information are very useful to quickly understand the code.
From what I've seen in Pharo, variables are usually named after their meaning, while method argument are named after their type, but in an ideal world I would like to know both the type and the meaning of both the variables and the arguments.
That's in my opinion one of the advantages of explicit types for reading code: you write the type besides the variable/argument, so the name of the variable/argument can describe its meaning and I have both informations.
As the Dan Luu overview of studies tend to show ( https://danluu.com/empirical-pl/), one outcome is that, yes, types help to understand the program whatever the language. But types need not be static declarations. They can be in comments, in variable names, or other kind of documentation (that's one reason why class comments matters IMO!). Where this information lies in Smalltalk depends on the kind of variable. - For method arguments, semantic is given by accompanying keyword, like (name: aString). Since methods are short (they should be!) this association is mentally preserved while reading code. The problem comes when the argument can be polymorphic, like aValuable. My recommendation is to document expectations in method comment if it can't be inferred simply. "aValuable: any object understanding value: (a 1-arg block, a Symbol, an Association, ...)" - For instance variables, the name carries a semantic: my personnal recommendation is that the expected type SHOULD be documented in class comment. Once upon a time (st80 years) classes were quite well documented. If it's not the case, you have to browe the inst.var. writers, and thus you fall back to the last case of temporary vriables below. Lacking or incomplete class comments is a criterion of quality... - For temporary variables, you generally either instantiate a class, use a literal or send a message to another variable. In the later case, the problem is to infer the type of returned object, which might involve tracking message chains and class comments. My experience is that this participates to the flat learning curve for beginners. At the beginning, we spend a lot of time exploring the message flow, but once the library is familiar, we don't. But this process has a virtue: it gives a deeper understanding on how things work, and IMO it's beneficial in the long term. Personnally, it participated to the pleasure of programming in Smalltalk. Static typing may help the IDE (refactoring and navigating).
My POV is thus that you enter this information for the tools, not for the humans (compiler, navigator, refactoring engine, ...).
I have differently tainted colleagues still thinking that the type help them reading code... So, IMO, this assertion reflects the dominant culture rather than intrinsic merits. IOW, if you want to create a successfull language, just clone an existing one :(
I would agree with your colleagues. I got stuck countless times when reading pharo code, because there was a message send to a variable I didn't know the type of, so I couldn't know which method was being called (because there were multiple methods with that name in the system). So the only solution was to place a breakpoint and get that method to be executed. This is not so easy (at least for me) in programs that are not really simple, because: 1) I need to have this method executed in its "normal use environment". I can't just execute it with dummy values as argument, because that will affect the values the variables will take. 2) I can look into tests, but since I don't know the program, I have no idea which tests to run to execute the piece of code. So in general, it's either asking someone that knows how the program work, or spending a lot of (annoying) time figuring out how the entire program flows values to get the type of that one variable.
Thomas
My experience is that the difficulty for inferring types comes from mega-morphic messages, or messages with false polymorphism. If things are difficult for a type inferencer, it will be difficult for us too. The advantage we have over an automated type-inferencer is if we can infer the type from the semantic, but that indeed requires prior knowledge of the library in use... My conclusion in the case you describe is that you have dealed with complex libraries (maybe with very abstract objects) that would hence deserve more documentation. The problem is worse if you are still in the learning curve for the base Smalltalk libraries (Collection, Stream, Number, ...). I will remind that one drawback of having static type declarations is to severly limit the evolution of the library. For example, once upon a time we had: Collection>>collect: aBlock But we then hacked: Symbol>>value: anObject ^anObject perform: self enabling things like (points collect: #x). If you have static declarations, you can't use such hack untill you rewrite all the type information in the whole Collection library and that's impracticle. Note that we did not take time to rewrite all the type hint information like this Collection>>collect: aBlockOrSymbol or with a neologism: Collection>>collect: aValuable The neologism would help only if properly documented, because it's not a class name, but rather an expectation that the object provides a certain API. The information that we can use a Symbol because (partly) polymorphic with BlockClosure is completely implicit. This has to be learned from tutorials or from reading code examples. One important quality in such case for the library is to have the most uniform rules possible for those conventions.
Thomas Dupriez wrote
I got stuck countless times when reading pharo code, because there was a message send to a variable I didn't know the type of, so I couldn't know which method was being called (because there were multiple methods with that name in the system). So the only solution was to place a breakpoint and get that method to be executed.
That is an interesting perspective. I usually browse senders. This almost* always seems to work, except when the message selector is very generic and reused in different contexts (e.g. #next) ----- Cheers, Sean -- Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html
On 9 Jun 2018, at 00:58, Sean P. DeNigris <sean@clipperadams.com> wrote:
Thomas Dupriez wrote
I got stuck countless times when reading pharo code, because there was a message send to a variable I didn't know the type of, so I couldn't know which method was being called (because there were multiple methods with that name in the system). So the only solution was to place a breakpoint and get that method to be executed.
That is an interesting perspective. I usually browse senders. This almost* always seems to work, except when the message selector is very generic and reused in different contexts (e.g. #next)
then you can scope your senders. There are 99% of possibilities your message is sent within the context of the class or package you are looking for. Esteban
----- Cheers, Sean -- Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html
Hi Esteban, Le 09/06/2018 à 08:37, Esteban Lorenzano a écrit :
On 9 Jun 2018, at 00:58, Sean P. DeNigris <sean@clipperadams.com> wrote:
Thomas Dupriez wrote
I got stuck countless times when reading pharo code, because there was a message send to a variable I didn't know the type of, so I couldn't know which method was being called (because there were multiple methods with that name in the system). So the only solution was to place a breakpoint and get that method to be executed.
That is an interesting perspective. I usually browse senders. This almost* always seems to work, except when the message selector is very generic and reused in different contexts (e.g. #next)
then you can scope your senders. There are 99% of possibilities your message is sent within the context of the class or package you are looking for.
Then a simple question is: - how do you scope your senders of command? A typical discovery / new user will do "senders of" first, and then discover the result is far too large. Now, does he has to backtrack on its exploration, choose a scope and call 'senders of' again? Thierry
Esteban
----- Cheers, Sean -- Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html
On 9 Jun 2018, at 08:45, Thierry Goubier <thierry.goubier@gmail.com> wrote:
Hi Esteban,
Le 09/06/2018 à 08:37, Esteban Lorenzano a écrit :
On 9 Jun 2018, at 00:58, Sean P. DeNigris <sean@clipperadams.com> wrote:
Thomas Dupriez wrote
I got stuck countless times when reading pharo code, because there was a message send to a variable I didn't know the type of, so I couldn't know which method was being called (because there were multiple methods with that name in the system). So the only solution was to place a breakpoint and get that method to be executed.
That is an interesting perspective. I usually browse senders. This almost* always seems to work, except when the message selector is very generic and reused in different contexts (e.g. #next) then you can scope your senders. There are 99% of possibilities your message is sent within the context of the class or package you are looking for.
Then a simple question is:
- how do you scope your senders of command?
A typical discovery / new user will do "senders of" first, and then discover the result is far too large.
calypso has the possibility of scoping after look for senders. there is a drop box there (but it can be enhanced, often I want to scope several packages, not just one)
Now, does he has to backtrack on its exploration, choose a scope and call 'senders of' again?
nope. Esteban
Thierry
Esteban
----- Cheers, Sean -- Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html
EstebanLM wrote
A typical discovery / new user will do "senders of" first, and then discover the result is far too large. calypso has the possibility of scoping after look for senders. â¦often I want to scope several packages
Ah! Now I understand the purpose of that feature better, but indeed multi-package selection is a must. ----- Cheers, Sean -- Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html
On 8 June 2018 at 23:06, Thomas Dupriez <thomas.dupriez@ens-paris-saclay.fr> wrote:
Hello, I wanted to just write a quick comment, but it turned into an essay, sorry. ^^
Le 08/06/2018 à 16:35, Nicolas Cellier a écrit :
2018-06-08 14:50 GMT+02:00 Thierry Goubier <thierry.goubier@gmail.com>:
Note that this is used in Smalltalk, when you write anInteger, aString : you're using a form of typing for documentation.
Exactly!
And if you transpose this style to static typing you get things like Cat *theCat = new Cat; Being tainted, I always thought that is was noise... You'd better rename your variable felix;)
Naming variables/arguments according to their type is only half a solution I think. Because there are actually two things I would like to know about a variable/argument when reading code: its type and its meaning. For example, knowing that an argument named "anInt" is an integer is nice, but I would also like to know that it's the number of dice the method has to roll. The two information are very useful to quickly understand the code.
From what I've seen in Pharo, variables are usually named after their meaning, while method argument are named after their type, but in an ideal world I would like to know both the type and the meaning of both the variables and the arguments.
That's in my opinion one of the advantages of explicit types for reading code: you write the type besides the variable/argument, so the name of the variable/argument can describe its meaning and I have both informations.
Static typing may help the IDE (refactoring and navigating). My POV is thus that you enter this information for the tools, not for the humans (compiler, navigator, refactoring engine, ...).
I have differently tainted colleagues still thinking that the type help them reading code... So, IMO, this assertion reflects the dominant culture rather than intrinsic merits. IOW, if you want to create a successfull language, just clone an existing one :(
I would agree with your colleagues. I got stuck countless times when reading pharo code, because there was a message send to a variable I didn't know the type of, so I couldn't know which method was being called (because there were multiple methods with that name in the system). So the only solution was to place a breakpoint and get that method to be executed. This is not so easy (at least for me) in programs that are not really simple, because: 1) I need to have this method executed in its "normal use environment". I can't just execute it with dummy values as argument, because that will affect the values the variables will take.
Has anyone looked at capturing all types assigned to variables while unit tests are running? What mechanisms do we have available that might help do this? Then we might hovering over a variable to display the percentage actual occurrence of types in that variable. (A side effect is this could be an indication of test code coverage.)
2) I can look into tests, but since I don't know the program, I have no idea which tests to run to execute the piece of code.
Makes me think a useful feature would be "what tests run that pass this point", and run one of them breaking at "this point". Then you'd quickly have a live stack to peruse. cheers -ben
Hi Ben, Le 09/06/2018 à 10:21, Ben Coman a écrit :
On 8 June 2018 at 23:06, Thomas Dupriez <thomas.dupriez@ens-paris-saclay.fr <mailto:thomas.dupriez@ens-paris-saclay.fr>> wrote:
Hello, I wanted to just write a quick comment, but it turned into an essay, sorry. ^^
Le 08/06/2018 à 16:35, Nicolas Cellier a écrit :
2018-06-08 14:50 GMT+02:00 Thierry Goubier <thierry.goubier@gmail.com <mailto:thierry.goubier@gmail.com>>:
Note that this is used in Smalltalk, when you write anInteger, aString : you're using a form of typing for documentation.
Exactly!
And if you transpose this style to static typing you get things like    Cat *theCat = new Cat; Being tainted, I always thought that is was noise... You'd better rename your variable felix;)
Naming variables/arguments according to their type is only half a solution I think. Because there are actually two things I would like to know about a variable/argument when reading code: its type and its meaning. For example, knowing that an argument named "anInt" is an integer is nice, but I would also like to know that it's the number of dice the method has to roll. The two information are very useful to quickly understand the code.
From what I've seen in Pharo, variables are usually named after their meaning, while method argument are named after their type, but in an ideal world I would like to know both the type and the meaning of both the variables and the arguments.
That's in my opinion one of the advantages of explicit types for reading code: you write the type besides the variable/argument, so the name of the variable/argument can describe its meaning and I have both informations.
Static typing may help the IDE (refactoring and navigating). My POV is thus that you enter this information for the tools, not for the humans (compiler, navigator, refactoring engine, ...).
I have differently tainted colleagues still thinking that the type help them reading code... So, IMO, this assertion reflects the dominant culture rather than intrinsic merits. IOW, if you want to create a successfull language, just clone an existing one :(
I would agree with your colleagues. I got stuck countless times when reading pharo code, because there was a message send to a variable I didn't know the type of, so I couldn't know which method was being called (because there were multiple methods with that name in the system). So the only solution was to place a breakpoint and get that method to be executed. This is not so easy (at least for me) in programs that are not really simple, because: 1) I need to have this method executed in its "normal use environment". I can't just execute it with dummy values as argument, because that will affect the values the variables will take.
Has anyone looked at capturing all types assigned to variables while unit tests are running?
Yes. A code trace tool like mine can provides you with that. Determining which variables have to be tracked is a bit complex if the developper doesn't provides that information.
What mechanisms do we have available that might help do this?
Metalinks, your usual trace tool code rewriting techniques, even RB. I have been unsuccessfull at using metalinks for heavy (many, many probes) method instrumentation. Metalinks and my trace tool more or less produces the same code, as far as the vm is concerned.
Then we might hovering over a variable to display the percentage actual occurrence of types in that variable.
If you equates type with class, that is.
(A side effect is this could be an indication of test code coverage.)
Thierry
2) I can look into tests, but since I don't know the program, I have no idea which tests to run to execute the piece of code.
Makes me think a useful feature would be "what tests run that pass this point", and run one of them breaking at "this point". Then you'd quickly have a live stack to peruse.
cheers -ben
In Smalltalk, you understand code by running it. Not just reading it. Set a breakpoint. When the debugger hits it, just step, enter, jump and see the code in live action. You almost never need to exit the debugger. Rewind as often as you like. You can even save the image with the debugger active. When you restart, you in the debugger where you left off. You can change code outside the debugger and come back to run the new code. Always remain in the debugger as much as possible. All the best, Aik-Siong Koh -- Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html
2018-06-08 14:29 GMT+02:00 Ben Coman <btc@openinworld.com>: ...
P.S. Then I bumped into "Toward Semantic Foundations for Program Editors" (https://arxiv.org/pdf/1703.08694.pdf) which was over my head but I guess it might be interesting to people working in UI area.
Interesting, and not that complex when you look at it in a greater scheme of things (once you get past their complexity of incomplete programs layer). However, some of the stuff seems hard to solve (all of it is about finding what could fill the holes of an incomplete program, according to your definition of what an incomplete program is... their's is not Smalltalk's) Once you have a theory about finding what could be in those holes, then some of it can be solved elegantly. And, in some theories, you have excellent results (i.e. formally sound, and fast in practice) on determining what could be in the holes. Thanks for the link, Thierry
participants (7)
-
askoh -
Ben Coman -
Esteban Lorenzano -
Nicolas Cellier -
Sean P. DeNigris -
Thierry Goubier -
Thomas Dupriez