Pharo-dev
By thread
pharo-dev@lists.pharo.org
By month
Messages by month
- ----- 2026 -----
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 1 participants
- 144613 messages
Re: PharoJ now available for Pharo10
by Esteban Lorenzano
that's nice... specially taking into account that Pharo10 does not yet exits :P
Esteban
On Apr 1 2021, at 1:38 pm, Noury Bouraqadi <bouraqadi(a)gmail.com> wrote:
> Hi everyone,
>
> We continue to make progress during our weekly coding sessions. We are glad to announce that this week we made a huge leap forward. Now PharoJS is available for Pharo 10. To install it, run the following script in a Pharo 10 playground
> Metacello new
> baseline: 'PharoJS';
> repository: 'github://PharoJS/PharoJS:pharo10';
> load
April 1, 2021
PharoJ now available for Pharo10
by Noury Bouraqadi
Hi everyone,
We continue to make progress during our weekly coding sessions. We are glad to announce that this week we made a huge leap forward. Now PharoJS is available for Pharo 10. To install it, run the following script in a Pharo 10 playground
Metacello new
baseline: 'PharoJS';
repository: 'github://PharoJS/PharoJS:pharo10';
load
April 1, 2021
Re: Improving Variable Shadow model
by Marcus Denker
# Adding a Release Test
This whole exploration of Variable Shadowing started with a bug report. It would be nice to never have cases
of shadowed variables. To make sure we never introduce them again, we can add a test to the ReleaseTest package.
Just looking a bit at other tests checking something for each method and starting with it as a template,
we can easily now implement #testNoShadowedVariablesInMethods:
```Smalltalk
testNoShadowedVariablesInMethods
"Fail if there are methods who define shadowed temps or args"
| found validExceptions remaining |
found := SystemNavigation default allMethodsSelect: [ :m |
m ast variableDefinitionNodes anySatisfy: [ :node | node variable isShadowing ] ].
"No other exceptions beside the ones mentioned here should be allowed"
validExceptions := {
RBDummyRefactoryTestDataApp>>#tempVarOverridesInstVar.
RBRefactoryTestDataApp>>#tempVarOverridesInstVar.
RBSmalllintTestObject>>#tempVarOverridesInstVar.
ReTempVarOverridesInstVarRuleTest>>#sampleMethod:}.
remaining := found asOrderedCollection
removeAll: validExceptions;
yourself.
self
assert: remaining isEmpty
description: ('the following methods have shadowing variable definitions and should be cleaned: ', remaining asString)
```
Of course I first ran with empty validExceptions, then I added all as these methods are examples from tests that test handling
of variable shadowing.The test is green! PR: https://github.com/pharo-project/pharo/pull/8927
# Shadowed Variables on the level of the class
We should think about Shadowed Variables on the level of a class
Classes define instance variables (modeled by sub-instances of Slot) and Class Variables (sub-instances of ClassVariable). They can shadow variables from the environment that the class is in (in the usual case this is Smalltalk Globals).
We should extend the concept of Shadowed variables to cover these cases, too.
Imagine we have a class that has a class variable "Person". Then we add a class named "Person": The class variable is now shadowing the class. #isShadowing for now is just checking for the property. But here we run into a problem: who could set the property? The classbuilder could do it. But adding a class would mean that we would need to check all existing classes if the new global is shadowed somewhere.
And we would not just have to check the classes: nothing forbids us to use a block argument "Person"... (even though bad style). Thus we would need to re-analyse all code globally. Not a good idea in a system where a user might have >100K classes...
Thus: we need to rethink our solution. It was not wrong: we were concened with just modeling shadowing for methods, the solution to tag the variables was a good one for that use. But now we need to step back. What is shadowing again? It means that the outer scope of a variable has already a variable of the same name.
Interestingly, the variable model is already modeling all the needed information. Variables have a scope, the scope has a perent scope.
We can lookup vars by name with #lookupVar. We can just change #isShadowing to implement exactly "I shadow a variable if looking up my name in my outer scope returns a variable".
```Smalltalk
isShadowing
"I shadow a variable if looking up my name in the outer scope returns a variable"
^(self scope outerScope ifNotNil: [:outer | outer lookupVar: self name]) notNil
```
We just have to add a missing #outerScope method to Behavior (as the outer scope is called the "environment" here), and one to SystemDictonary returning nil.
And it works! The tests we did for shadowing are still green.
Pull request is here: https://github.com/pharo-project/pharo/pull/8931
With this in place, we can add a new Critique Rule. But that is for next time.
# TODO NEXT
⢠We should add a rule that checks of instance or class vars shadow globals
⢠We should add a release test to make sure we have no shadowed vars on the class level in the system
⢠All the rules should be further improved to exactly tell the user what is shadowed where, to make it easy to fix
> On 30 Mar 2021, at 18:18, Marcus Denker <marcus.denker(a)inria.fr> wrote:
>
> We merged this and did the next step:
>
> 8009-Rule-required-for-shadowed-variables #8917
> https://github.com/pharo-project/pharo/pull/8917
>
> Thus the Code critique now correctly shows shadowed variables even for the case where the argument of a closure
> shadows an other variables.
>
> ⢠The rule of course can now be further improved to exactly tell the user what is shadowed
> ⢠We should add a rule that checks of instance or class vars shadow globals (which needs further refinement on the shadow model)
> ⢠We should add a release test to make sure we have no shadowed vars in the system
> â both on the level of methods and on the level of Classes
>
> but that is for the future
>
>
>> On 29 Mar 2021, at 16:26, Marcus Denker <marcus.denker(a)inria.fr> wrote:
>>
>> The issue tracker entry "Rule required for shadowed variables" [#8009](https://github.com/pharo-project/pharo/issues/8009)
>>
>> It reads:
>>
>> ___
>>
>>
>> In the CI output log for PRs on Pharo 9 issues I see the following warnings on Roassal classes:
>>
>> SystemNotification: RSCanvas>>numberOfEdges(edges is shadowed)
>> SystemNotification: RSCanvas>>numberOfEdges(edges is shadowed)
>> SystemNotification: RSCanvas>>numberOfNodes(nodes is shadowed)
>> SystemNotification: RSCanvas>>numberOfNodes(nodes is shadowed)
>> SystemNotification: RSComposite>>numberOfEdges(edges is shadowed)
>> SystemNotification: RSComposite>>numberOfEdges(edges is shadowed)
>> SystemNotification: RSComposite>>numberOfNodes(nodes is shadowed)
>> SystemNotification: RSComposite>>numberOfNodes(nodes is shadowed)
>> SystemNotification: RSShape>>printOn:(model is shadowed)
>> SystemNotification: RSShape>>printOn:(model is shadowed)
>>
>> which means we have local variables (or block variable) in a method with the same name as an existing ivar in the class.
>>
>> These cases should be cleaned in Rossal3 for the Pharo 9 image - for that I opened https://github.com/ObjectProfile/Roassal3/issues/321 on Roassal3 issue tracker.
>>
>> But it would be good if we could have a Lint rule that shows that problem so one can avoid it:
>>
>> **Side note:** Yes - there already is a rule called ReTempVarOverridesInstVarRuleTest - but this is only for temps
>> and does not cover variables in blocks like in
>>
>> ```Smalltalk
>> numberOfEdges
>> "Return the number of edges contained in the container"
>> ^ self privateEdges
>> ifNil: [ 0 ]
>> ifNotNil: [ :edges | edges size ]
>> ```
>> when "edges" is already an instance variable
>>
>> ___
>>
>> So how is ReTempVarOverridesInstVarRuleTest implemented?
>>
>> ```Smalltalk
>> check: aMethod forCritiquesDo: aCriticBlock
>> | ivarNames problemTemps|
>> ivarNames := aMethod methodClass instVarNames.
>> ivarNames ifEmpty: [ ^ self ].
>>
>> problemTemps := ((aMethod ast arguments, aMethod ast temporaries)
>> select: [ :node |ivarNames includes: node name]).
>> problemTemps do: [ :node |
>> aCriticBlock cull: (self critiqueFor: aMethod about: node) ]
>> ```
>>
>> So, this test is done purely on the results of the compilation, it just checks if temps are overriding the instance vars.
>> It just does not care about blocks, nor class variables or globals.
>>
>> We could now, for this issue, recurse into the compiled block closures, but that would make the code quite complex.
>>
>> To see a better solution, let's check who actually prints out the log message in the build. Just searching for a substring will
>> lead us to OCShadowVariableWarning>>#variable:shadows:
>>
>> ```Smalltalk
>> variable: varNode shadows: semVar
>> compilationContext interactive
>> ifTrue: [
>> OCSemanticError new
>> node: node;
>> compilationContext: compilationContext;
>> messageText: self stringMessage;
>> signal ]
>> ifFalse: [ self showWarningOnTranscript ].
>>
>> ```
>>
>> This is an exception raised by the AST visitor that does name analysis, OCASTSemanticAnalyzer:
>>
>> ```Smalltalk
>> variable: variableNode shadows: semVar
>> compilationContext optionSkipSemanticWarnings ifTrue: [ ^semVar ].
>> ^ OCShadowVariableWarning new
>> node: variableNode;
>> shadowedVar: semVar;
>> compilationContext: compilationContext;
>> signal
>> ```
>>
>> This method is called whever we lookup a Variable name to create a Variable object describing it:
>>
>> ```Smalltalk
>> declareVariableNode: aVariableNode as: anOCTempVariable
>> | name var |
>> name := aVariableNode name.
>> var := scope lookupVarForDeclaration: name.
>> var ifNotNil: [
>> "Another variable with same name is visible from current scope.
>> Warn about the name clash and if proceed add new temp to shadow existing var"
>> self variable: aVariableNode shadows: var ].
>> var := scope addTemp: anOCTempVariable.
>> aVariableNode binding: var.
>> ^ var
>> ```
>>
>> This means: in non-interactive mode, we just log the error and compile while allowing shadowing. In interactive mode
>> we forbid it (we raise a OCSemanticError exception that will be displayed in the code editor).
>>
>> What could we now do to improve the model of shadowing variables? The best thing would be if we could add the fact that
>> a variable shadows another to the semantic information. That is, it should be modeled as part of the variable.
>>
>> We do not need much: just add this information as a property would be perfectly enough. This way we can add a test method
>> (that check if the property exists). On the level of the Code Critique rule it will be very simple: just get all variables
>> that are defined (args, temps, args of blocks) and check if they are shadowing. That's easy!
>>
>> So what is needed to implement it?
>>
>> We first need to make sure we hand over one more parameter to #variable:shadows: and call it later: right now, in
>> interactive mode, we never create a Variable at all. There is no problem to delay that and tag the variable correctly:
>>
>> ```Smalltalk
>> variable: aVariable shadows: shadowedVariable inNode: variableNode
>> aVariable shadowing: shadowedVariable.
>> compilationContext optionSkipSemanticWarnings ifTrue: [ ^aVariable ].
>> ^ OCShadowVariableWarning new
>> node: variableNode;
>> shadowedVar: aVariable;
>> compilationContext: compilationContext;
>> signal
>> ```
>>
>> with:
>>
>> ```Smalltalk
>> declareVariableNode: aVariableNode as: anOCTempVariable
>> | name var shadowed |
>> name := aVariableNode name.
>> var := scope lookupVarForDeclaration: name.
>> var ifNotNil: [
>> "Another variable with same name is visible from current scope"
>> shadowed := var.
>> ].
>> var := scope addTemp: anOCTempVariable.
>> aVariableNode binding: var.
>> shadowed ifNotNil: [self variable: var shadows: shadowed inNode: aVariableNode].
>> ^ var
>> ```
>>
>>
>> To be able to tag Variables, we implement
>>
>>
>> ```Smalltalk
>> shadowing: anotherVariable
>> self propertyAt: #shadows put: anotherVariable
>> ```
>>
>> and
>>
>> ```Smalltalk
>> "testing"
>> isShadowing
>> ^self hasProperty: #shadows
>> ```
>>
>> We do this on Variables, which means that we can later introduce Variable shadow tagging even for instance variables and Class Variables
>>
>> How do we now test this?
>>
>> One idea is to rewrite ReTempVarOverridesInstVarRule>>#check:forCritiquesDo: to use #isShadowing. ReTempVarOverridesInstVarRuleTest
>> is green, we have something that is reado to commit.
>>
>> Let's try
>>
>> ```Smalltalk
>> check: aMethod forCritiquesDo: aCriticBlock
>>
>> | problemTemps |
>> problemTemps := aMethod temporaryVariables select: [ :var |
>> var isShadowing ].
>> problemTemps do: [ :var |
>> aCriticBlock cull:
>> (self critiqueFor: aMethod about: var definingNode) ]
>> ```
>>
>> And: Success! This is now a first PR to be done [see here](https://github.com/pharo-project/pharo/pull/8909).
>>
>> This does not yet provide the Rule and the Release Test for shadowing vars in general, but it is a very nice first step that we can build upon next.
>>
>
April 1, 2021
Re: Improving Variable Shadow model
by Marcus Denker
We merged this and did the next step:
8009-Rule-required-for-shadowed-variables #8917
https://github.com/pharo-project/pharo/pull/8917
Thus the Code critique now correctly shows shadowed variables even for the case where the argument of a closure
shadows an other variables.
⢠The rule of course can now be further improved to exactly tell the user what is shadowed
⢠We should add a rule that checks of instance or class vars shadow globals (which needs further refinement on the shadow model)
⢠We should add a release test to make sure we have no shadowed vars in the system
â both on the level of methods and on the level of Classes
but that is for the future
> On 29 Mar 2021, at 16:26, Marcus Denker <marcus.denker(a)inria.fr> wrote:
>
> The issue tracker entry "Rule required for shadowed variables" [#8009](https://github.com/pharo-project/pharo/issues/8009)
>
> It reads:
>
> ___
>
>
> In the CI output log for PRs on Pharo 9 issues I see the following warnings on Roassal classes:
>
> SystemNotification: RSCanvas>>numberOfEdges(edges is shadowed)
> SystemNotification: RSCanvas>>numberOfEdges(edges is shadowed)
> SystemNotification: RSCanvas>>numberOfNodes(nodes is shadowed)
> SystemNotification: RSCanvas>>numberOfNodes(nodes is shadowed)
> SystemNotification: RSComposite>>numberOfEdges(edges is shadowed)
> SystemNotification: RSComposite>>numberOfEdges(edges is shadowed)
> SystemNotification: RSComposite>>numberOfNodes(nodes is shadowed)
> SystemNotification: RSComposite>>numberOfNodes(nodes is shadowed)
> SystemNotification: RSShape>>printOn:(model is shadowed)
> SystemNotification: RSShape>>printOn:(model is shadowed)
>
> which means we have local variables (or block variable) in a method with the same name as an existing ivar in the class.
>
> These cases should be cleaned in Rossal3 for the Pharo 9 image - for that I opened https://github.com/ObjectProfile/Roassal3/issues/321 on Roassal3 issue tracker.
>
> But it would be good if we could have a Lint rule that shows that problem so one can avoid it:
>
> **Side note:** Yes - there already is a rule called ReTempVarOverridesInstVarRuleTest - but this is only for temps
> and does not cover variables in blocks like in
>
> ```Smalltalk
> numberOfEdges
> "Return the number of edges contained in the container"
> ^ self privateEdges
> ifNil: [ 0 ]
> ifNotNil: [ :edges | edges size ]
> ```
> when "edges" is already an instance variable
>
> ___
>
> So how is ReTempVarOverridesInstVarRuleTest implemented?
>
> ```Smalltalk
> check: aMethod forCritiquesDo: aCriticBlock
> | ivarNames problemTemps|
> ivarNames := aMethod methodClass instVarNames.
> ivarNames ifEmpty: [ ^ self ].
>
> problemTemps := ((aMethod ast arguments, aMethod ast temporaries)
> select: [ :node |ivarNames includes: node name]).
> problemTemps do: [ :node |
> aCriticBlock cull: (self critiqueFor: aMethod about: node) ]
> ```
>
> So, this test is done purely on the results of the compilation, it just checks if temps are overriding the instance vars.
> It just does not care about blocks, nor class variables or globals.
>
> We could now, for this issue, recurse into the compiled block closures, but that would make the code quite complex.
>
> To see a better solution, let's check who actually prints out the log message in the build. Just searching for a substring will
> lead us to OCShadowVariableWarning>>#variable:shadows:
>
> ```Smalltalk
> variable: varNode shadows: semVar
> compilationContext interactive
> ifTrue: [
> OCSemanticError new
> node: node;
> compilationContext: compilationContext;
> messageText: self stringMessage;
> signal ]
> ifFalse: [ self showWarningOnTranscript ].
>
> ```
>
> This is an exception raised by the AST visitor that does name analysis, OCASTSemanticAnalyzer:
>
> ```Smalltalk
> variable: variableNode shadows: semVar
> compilationContext optionSkipSemanticWarnings ifTrue: [ ^semVar ].
> ^ OCShadowVariableWarning new
> node: variableNode;
> shadowedVar: semVar;
> compilationContext: compilationContext;
> signal
> ```
>
> This method is called whever we lookup a Variable name to create a Variable object describing it:
>
> ```Smalltalk
> declareVariableNode: aVariableNode as: anOCTempVariable
> | name var |
> name := aVariableNode name.
> var := scope lookupVarForDeclaration: name.
> var ifNotNil: [
> "Another variable with same name is visible from current scope.
> Warn about the name clash and if proceed add new temp to shadow existing var"
> self variable: aVariableNode shadows: var ].
> var := scope addTemp: anOCTempVariable.
> aVariableNode binding: var.
> ^ var
> ```
>
> This means: in non-interactive mode, we just log the error and compile while allowing shadowing. In interactive mode
> we forbid it (we raise a OCSemanticError exception that will be displayed in the code editor).
>
> What could we now do to improve the model of shadowing variables? The best thing would be if we could add the fact that
> a variable shadows another to the semantic information. That is, it should be modeled as part of the variable.
>
> We do not need much: just add this information as a property would be perfectly enough. This way we can add a test method
> (that check if the property exists). On the level of the Code Critique rule it will be very simple: just get all variables
> that are defined (args, temps, args of blocks) and check if they are shadowing. That's easy!
>
> So what is needed to implement it?
>
> We first need to make sure we hand over one more parameter to #variable:shadows: and call it later: right now, in
> interactive mode, we never create a Variable at all. There is no problem to delay that and tag the variable correctly:
>
> ```Smalltalk
> variable: aVariable shadows: shadowedVariable inNode: variableNode
> aVariable shadowing: shadowedVariable.
> compilationContext optionSkipSemanticWarnings ifTrue: [ ^aVariable ].
> ^ OCShadowVariableWarning new
> node: variableNode;
> shadowedVar: aVariable;
> compilationContext: compilationContext;
> signal
> ```
>
> with:
>
> ```Smalltalk
> declareVariableNode: aVariableNode as: anOCTempVariable
> | name var shadowed |
> name := aVariableNode name.
> var := scope lookupVarForDeclaration: name.
> var ifNotNil: [
> "Another variable with same name is visible from current scope"
> shadowed := var.
> ].
> var := scope addTemp: anOCTempVariable.
> aVariableNode binding: var.
> shadowed ifNotNil: [self variable: var shadows: shadowed inNode: aVariableNode].
> ^ var
> ```
>
>
> To be able to tag Variables, we implement
>
>
> ```Smalltalk
> shadowing: anotherVariable
> self propertyAt: #shadows put: anotherVariable
> ```
>
> and
>
> ```Smalltalk
> "testing"
> isShadowing
> ^self hasProperty: #shadows
> ```
>
> We do this on Variables, which means that we can later introduce Variable shadow tagging even for instance variables and Class Variables
>
> How do we now test this?
>
> One idea is to rewrite ReTempVarOverridesInstVarRule>>#check:forCritiquesDo: to use #isShadowing. ReTempVarOverridesInstVarRuleTest
> is green, we have something that is reado to commit.
>
> Let's try
>
> ```Smalltalk
> check: aMethod forCritiquesDo: aCriticBlock
>
> | problemTemps |
> problemTemps := aMethod temporaryVariables select: [ :var |
> var isShadowing ].
> problemTemps do: [ :var |
> aCriticBlock cull:
> (self critiqueFor: aMethod about: var definingNode) ]
> ```
>
> And: Success! This is now a first PR to be done [see here](https://github.com/pharo-project/pharo/pull/8909).
>
> This does not yet provide the Rule and the Release Test for shadowing vars in general, but it is a very nice first step that we can build upon next.
>
March 30, 2021
Menu separators on Glamour fastTable not working
by Federico.Balaguer
Hello!
I came across a problem with Glamour's fastTables, menu separators are not
displayed. I have a running example based on PBE2CodeEditor example that
shows the problem. I am not sure whether it makes sense to share that here.
I spent a couple of hours trying to find the code that generate the menues
with no luck (subclasses of GLMMorphicWidgetRenderer) .
Could someone give me a hint where to look at?
Thanks! Federico
--
Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html
March 30, 2021
Improving Variable Shadow model
by Marcus Denker
The issue tracker entry "Rule required for shadowed variables" [#8009](https://github.com/pharo-project/pharo/issues/8009)
It reads:
___
In the CI output log for PRs on Pharo 9 issues I see the following warnings on Roassal classes:
SystemNotification: RSCanvas>>numberOfEdges(edges is shadowed)
SystemNotification: RSCanvas>>numberOfEdges(edges is shadowed)
SystemNotification: RSCanvas>>numberOfNodes(nodes is shadowed)
SystemNotification: RSCanvas>>numberOfNodes(nodes is shadowed)
SystemNotification: RSComposite>>numberOfEdges(edges is shadowed)
SystemNotification: RSComposite>>numberOfEdges(edges is shadowed)
SystemNotification: RSComposite>>numberOfNodes(nodes is shadowed)
SystemNotification: RSComposite>>numberOfNodes(nodes is shadowed)
SystemNotification: RSShape>>printOn:(model is shadowed)
SystemNotification: RSShape>>printOn:(model is shadowed)
which means we have local variables (or block variable) in a method with the same name as an existing ivar in the class.
These cases should be cleaned in Rossal3 for the Pharo 9 image - for that I opened https://github.com/ObjectProfile/Roassal3/issues/321 on Roassal3 issue tracker.
But it would be good if we could have a Lint rule that shows that problem so one can avoid it:
**Side note:** Yes - there already is a rule called ReTempVarOverridesInstVarRuleTest - but this is only for temps
and does not cover variables in blocks like in
```Smalltalk
numberOfEdges
"Return the number of edges contained in the container"
^ self privateEdges
ifNil: [ 0 ]
ifNotNil: [ :edges | edges size ]
```
when "edges" is already an instance variable
___
So how is ReTempVarOverridesInstVarRuleTest implemented?
```Smalltalk
check: aMethod forCritiquesDo: aCriticBlock
| ivarNames problemTemps|
ivarNames := aMethod methodClass instVarNames.
ivarNames ifEmpty: [ ^ self ].
problemTemps := ((aMethod ast arguments, aMethod ast temporaries)
select: [ :node |ivarNames includes: node name]).
problemTemps do: [ :node |
aCriticBlock cull: (self critiqueFor: aMethod about: node) ]
```
So, this test is done purely on the results of the compilation, it just checks if temps are overriding the instance vars.
It just does not care about blocks, nor class variables or globals.
We could now, for this issue, recurse into the compiled block closures, but that would make the code quite complex.
To see a better solution, let's check who actually prints out the log message in the build. Just searching for a substring will
lead us to OCShadowVariableWarning>>#variable:shadows:
```Smalltalk
variable: varNode shadows: semVar
compilationContext interactive
ifTrue: [
OCSemanticError new
node: node;
compilationContext: compilationContext;
messageText: self stringMessage;
signal ]
ifFalse: [ self showWarningOnTranscript ].
```
This is an exception raised by the AST visitor that does name analysis, OCASTSemanticAnalyzer:
```Smalltalk
variable: variableNode shadows: semVar
compilationContext optionSkipSemanticWarnings ifTrue: [ ^semVar ].
^ OCShadowVariableWarning new
node: variableNode;
shadowedVar: semVar;
compilationContext: compilationContext;
signal
```
This method is called whever we lookup a Variable name to create a Variable object describing it:
```Smalltalk
declareVariableNode: aVariableNode as: anOCTempVariable
| name var |
name := aVariableNode name.
var := scope lookupVarForDeclaration: name.
var ifNotNil: [
"Another variable with same name is visible from current scope.
Warn about the name clash and if proceed add new temp to shadow existing var"
self variable: aVariableNode shadows: var ].
var := scope addTemp: anOCTempVariable.
aVariableNode binding: var.
^ var
```
This means: in non-interactive mode, we just log the error and compile while allowing shadowing. In interactive mode
we forbid it (we raise a OCSemanticError exception that will be displayed in the code editor).
What could we now do to improve the model of shadowing variables? The best thing would be if we could add the fact that
a variable shadows another to the semantic information. That is, it should be modeled as part of the variable.
We do not need much: just add this information as a property would be perfectly enough. This way we can add a test method
(that check if the property exists). On the level of the Code Critique rule it will be very simple: just get all variables
that are defined (args, temps, args of blocks) and check if they are shadowing. That's easy!
So what is needed to implement it?
We first need to make sure we hand over one more parameter to #variable:shadows: and call it later: right now, in
interactive mode, we never create a Variable at all. There is no problem to delay that and tag the variable correctly:
```Smalltalk
variable: aVariable shadows: shadowedVariable inNode: variableNode
aVariable shadowing: shadowedVariable.
compilationContext optionSkipSemanticWarnings ifTrue: [ ^aVariable ].
^ OCShadowVariableWarning new
node: variableNode;
shadowedVar: aVariable;
compilationContext: compilationContext;
signal
```
with:
```Smalltalk
declareVariableNode: aVariableNode as: anOCTempVariable
| name var shadowed |
name := aVariableNode name.
var := scope lookupVarForDeclaration: name.
var ifNotNil: [
"Another variable with same name is visible from current scope"
shadowed := var.
].
var := scope addTemp: anOCTempVariable.
aVariableNode binding: var.
shadowed ifNotNil: [self variable: var shadows: shadowed inNode: aVariableNode].
^ var
```
To be able to tag Variables, we implement
```Smalltalk
shadowing: anotherVariable
self propertyAt: #shadows put: anotherVariable
```
and
```Smalltalk
"testing"
isShadowing
^self hasProperty: #shadows
```
We do this on Variables, which means that we can later introduce Variable shadow tagging even for instance variables and Class Variables
How do we now test this?
One idea is to rewrite ReTempVarOverridesInstVarRule>>#check:forCritiquesDo: to use #isShadowing. ReTempVarOverridesInstVarRuleTest
is green, we have something that is reado to commit.
Let's try
```Smalltalk
check: aMethod forCritiquesDo: aCriticBlock
| problemTemps |
problemTemps := aMethod temporaryVariables select: [ :var |
var isShadowing ].
problemTemps do: [ :var |
aCriticBlock cull:
(self critiqueFor: aMethod about: var definingNode) ]
```
And: Success! This is now a first PR to be done [see here](https://github.com/pharo-project/pharo/pull/8909).
This does not yet provide the Rule and the Release Test for shadowing vars in general, but it is a very nice first step that we can build upon next.
March 29, 2021
Progress Report -> Refactoring Project - ( March 22 - 26 )
by Evelyn Cusi Lopez
Hello all,
Last week I did these tasks:
- Fix issue: "Improve Extract SetUp Refactoring
<https://github.com/pharo-project/pharo/issues/8853>", now this refactoring
can find and replace #setUp occurrences in all methods tests. Check PR to
know the changes <https://github.com/pharo-project/pharo/pull/8877>. You
can see the new behavior of refactoring in the following video:
https://www.youtube.com/watch?v=feKsdci0dL4
- Fix issue: "Add preview to extract method Refactoring
<https://github.com/pharo-project/pharo/issues/8851>". Check PR to know the
changes <https://github.com/pharo-project/pharo/pull/8898>. You can see
the new behavior of refactoring in the following video:
https://www.youtube.com/watch?v=J0Qexh9l034
- Fix issues: "Replace senders refactoring can only replace senders with
same amount of arguments #5851
<https://github.com/pharo-project/pharo/issues/5851>" and " Improving
refactoring: how to merge on method usage into another #2493
<https://github.com/pharo-project/pharo/issues/2493>", now we can replace
method's senders with different amount of arguments . Check PR to know the
changes <https://github.com/pharo-project/pharo/pull/8903>. You can see
the new behavior of refactoring in the following video:
https://www.youtube.com/watch?v=zPzUHFWWpV4
- Start to fix RB - Improve instance variable refactoring #8665
<https://github.com/pharo-project/pharo/issues/8665>
Tasks for this week:
- Finish to fix: RB - Improve instance variable refactoring #8665
<https://github.com/pharo-project/pharo/issues/8665>
- Fix issue: Extract method in the superclass is not fully working #8871
<https://github.com/pharo-project/pharo/issues/8871>
- Add option to use scopes in refactorings.
- Add previews for refactoring, using a scope's selector to apply the
refactoring.
- Fix issue: move to component refactoring issue.
<https://github.com/pharo-project/pharo/issues/8499>
- Fix issue: Inline senders refactoring does not correctly manage errors
#6218 <https://github.com/pharo-project/pharo/issues/6218>
Regards,
Evelyn C.
March 29, 2021
This week (12/2021) on the Pharo Issue Tracker
by Marcus Denker
We merged 20 Pull Requests and closed 18 Issue tracker entries this week.
https://github.com/pharo-project/pharo/pulse
Refactoring Infrastructure
============
- RB - Rename vars traits #8848
https://github.com/pharo-project/pharo/pull/8848
- RB - Improve extract method #8847
https://github.com/pharo-project/pharo/pull/8847
- RB - Remove senders of method Refactoring #8843
https://github.com/pharo-project/pharo/pull/8843
- RB - Add comments to RBRemoveAllSendersRefactoring #8857
https://github.com/pharo-project/pharo/pull/8857
- RB - Fix message of Extract Method Refactoring #8872
https://github.com/pharo-project/pharo/pull/8872
Fixes
=====
- 8655-SurfacePluginDLL-is-crashing-with-the-headless-VM-at-restart #8804
https://github.com/pharo-project/pharo/pull/8804
- Fluid class should propose trait: + trait: TEmpty as a default #8674
https://github.com/pharo-project/pharo/pull/8674
- Fix 8855: Paste shortcut (cmd/ctrl+V) conflicts with new calypso shortcut #8856
https://github.com/pharo-project/pharo/pull/8856
- in white theme, ghost text should be darker (otherwise is not visible) #8859
https://github.com/pharo-project/pharo/pull/8859
- 8762-Compiler-Evaluating-an-expression-with-error-with-a-requestor-leads-to-primitive-fail #8800
https://github.com/pharo-project/pharo/pull/8800
- 6526-RGTraitDescriptionStrategy-invoke-methods-that-do-not-exist-announcer #8841
https://github.com/pharo-project/pharo/pull/8841
- Little fix in OSWindowGestureHandler>>trackFinger: #8881
https://github.com/pharo-project/pharo/pull/8881
Features
========
Just two methods added to get information from the system
- Add CairoLibrary>>versionString #8880
https://github.com/pharo-project/pharo/pull/8880
- Add VirtualMachine>>#freeSize #8868
https://github.com/pharo-project/pharo/pull/8868
Cleanups and Refactorings
====================
- Update-ReleaseTests #8849
https://github.com/pharo-project/pharo/pull/8849
- Categorize uncategorized methods in classes starting with H #8858
https://github.com/pharo-project/pharo/pull/8858
- comment typos #8866
https://github.com/pharo-project/pharo/pull/8866
- Simplify SystemVersion class>>#current #8863
https://github.com/pharo-project/pharo/pull/8863
- [Calypso] Refactor and bugfix on ClySystemEnvironment #8867
https://github.com/pharo-project/pharo/pull/8867
- add test for Array2D zeros method #8873
https://github.com/pharo-project/pharo/pull/8873
March 26, 2021
Proposal: Simplify How Pragmas are stored
by Marcus Denker
In Pharo9, we have speed up Pragma access.
https://blog.marcusdenker.de/speeding-up-pragma-access
https://blog.marcusdenker.de/speeding-up-pragma-access-part-ii
I think we further improve things, this time with regard to how Pragmas are stored in the method objects.
**Describe the problem**
Pragmas are stored mixed with associations in the AdditionalMethodState. I propose to store all Pragmas as one pre-allocated
array as a property #pragmas instead.
This will speedup both pragma access and property access and will radically simplify the code.
**Classes involved**
CompiledMethod, AdditionalMethodState, Compiler backed
**Current Situation**
This is how Pragmas are now stored. It is a bit strange:
- if there is a pragma, we create a method with an AdditionalMethodState object, referenced from the second-last literal.
- This is a variable subclass, implementing a dictionary, no hashing, just linear search (that is ok as dicts <10 are faster without hashing most likely)
- What is *very* strange: it contains associations (for properties) and Pragmas, mixed.
This means that all code very odd as it has to always check:
```smalltalk
propertyAt: aKey ifAbsent: aBlock
"Answer the property value associated with aKey or, if aKey isn't found, answer the result of evaluating aBlock."
1 to: self basicSize do: [:i |
| propertyOrPragma "<Association|Pragma>" |
propertyOrPragma := self basicAt: i.
(propertyOrPragma isAssociation
and: [propertyOrPragma key == aKey]) ifTrue:
[^propertyOrPragma value]].
^aBlock value
```
while we have a second api that gives us either a pragma or a property, whatever it finds first:
```smalltalk
at: aKey ifAbsent: aBlock
"Answer the property value or pragma associated with aKey or,
if aKey isnt found, answer the result of evaluating aBlock."
1 to: self basicSize do:
[:i |
| propertyOrPragma "<Association|Pragma>" |
(propertyOrPragma := self basicAt: i) key == aKey ifTrue:
[^propertyOrPragma isAssociation
ifTrue: [propertyOrPragma value]
ifFalse: [propertyOrPragma]]].
^aBlock value
```
and if you ask for #pragmas (which is the main API), it has to create the array, iterating and checking for each entry:
```smalltalk
pragmas
"Return the Pragma objects. Properties are stored as Associations"
^ Array new: self basicSize streamContents: [ :pragmaStream |
1 to: self basicSize do: [ :i |
| propertyOrPragma "<Association|Pragma>" |
(propertyOrPragma := self basicAt: i) isAssociation ifFalse: [
pragmaStream nextPut: propertyOrPragma ] ] ]
```
This is slow for pragmas, the array is created on demand. This is slow for properties, as we need to check an skip pragmas when searching.
For speed, the code for pragmas on CompiledMethod has to do that:
```smalltalk
pragmas
| selectorOrProperties |
^(selectorOrProperties := self penultimateLiteral) isMethodProperties
ifTrue: [selectorOrProperties pragmas]
ifFalse: [#()]
```
Just to avoid creating an empty array via the streamContents: method. Which, if you ask for pragmas of all methods, does matter. And this is what "Senders Of" does...
And this is very, very strange. In the past this lead to very odd things like "sender of" for #isFFIMethod giving all method that had the property #isFFIMethod set. (I fixed that already)
I propose to clean this up.
**Proposal**
I want to have a clear layer: properties are there to add state to CompiledMethods, the Pragma implementation just uses
this lower level layer.
AdditionalMethodState should have *no* code related to Pragmas.
So instead of putting pragmas into the AdditionalMethodState directly, we just add one property #pragmas for those methods
where pragmas are used. The compiler then pre-allocates the array and puts it there. (Pragmas are statically known, properties
can be set and removed at runtime).
Which means that on CompiledMethod, we just have:
```smalltalk
pragmas
^ self propertyAt: #pragmas ifAbsent: [ #() ]
```
pragmas and pragmasDo: on AdditionalMethodState can be removed, we can remove the propertyAt* API there and just use
the Dictionary API (which makes sense, as AdditionalMethodState is just a property dictionary with a backpointer)
The only thing we need to do for this to work is to change the code in the compiler backend to be:
```smalltalk
addPragma: aPragma
properties ifNil: [ properties := AdditionalMethodState new ].
properties
at: #pragmas
ifAbsent: [ properties := properties copyWith: #pragmas -> #( ) ].
properties
at: #pragmas
put: ((properties at: #pragmas) copyWith: aPragma)
```
(bit ugly... need to use copyWith: as the high level API needs the compiledMethod set in the AdditionalMethodState)
And some smaller changes here and there (e.g. setting the backpointer in pragmas after the compiledMethod is created).
I did first implementation, It seems to work but this showed that we have to take care with the bootrap.
(see [here](https://github.com/pharo-project/pharo/pull/7930/files) for the closed PR)
March 24, 2021
[ANN] Next Pharo Sprint: March 26
by Marcus Denker
We will organize a Pharo sprint / Moose dojo March 26
Goals of this sprint:
- Fix issues from tracker https://github.com/pharo-project/pharo/issues
This is a Remote Sprint, it happens on Discord.
http://pharo.org/contribute-events
We have added a Board to coordinate the work:
https://github.com/orgs/pharo-project/projects/9
A list of all Pharo Event of the year an be found here: https://association.pharo.org/events
March 24, 2021