Boo

Change default field visibility from protected to private

Details

  • Type: Improvement Improvement
  • Status: Resolved Resolved
  • Priority: Minor Minor
  • Resolution: Won't Fix
  • Affects Version/s: 0.8.2
  • Fix Version/s: 0.9
  • Component/s: None
  • Labels:
    None
  • Number of attachments :
    0

Description

Currently the default visibility for fields in boo is protected.
This is not considered a proper OOP practice and as such get caught by static analysis tools such as Gendarme (rule: AvoidVisibleFields) or FXCop (rule: CA1051-DoNotDeclareVisibleInstanceFields).

Indeed, fields should be local implementation details only. A protected field publishes its interface outside the assembly and thus can be used as such by derived types outside of the assembly, which obviously causes bad coupling and can cause unnoticed/unwanted breakage when the implementation detail in the 'mother' assembly changed.

Since 0.9 will be a slightly "breaking" release already (ambiguous syntax for generic declarations, among other minor things I guess), I think we should take the opportunity to also do this change.

The change will almost be non-breaking anyway since any current field with default protected will work as well when changed to internal. It would break only code if any using protected fields from another assembly, which would be something nice to notice/fix anyway.

Thoughts?

Issue Links

Activity

Hide
Cedric Vivier added a comment -

No comment means no strong opinion against this?

Show
Cedric Vivier added a comment - No comment means no strong opinion against this?
Hide
Avishay Lavie added a comment -

I agree that fields should be private by default, and that 0.9 is a good time to change that. I suspect Bamboo would feel otherwise, though.

Show
Avishay Lavie added a comment - I agree that fields should be private by default, and that 0.9 is a good time to change that. I suspect Bamboo would feel otherwise, though.
Hide
Cedric Vivier added a comment - - edited

Oh I do not suggest changing them 'private' (though that would be my preferred choice too, hence BOO-1091 ).
'internal' would actually be even more permissive than 'protected' within the same assembly.

But I think this is a good tradeoff since it :

  • does not break anything, changing to private would obviously break a lot of code (and would make prototyping/subclassing 'harder')
  • allows quick prototyping (within the same assembly), sounds boo-ish to me.
  • does not, as currently, create 'by default' an unwanted/unnoticed/undesirable visible API usable by external code (this the main problem of current default imho)
  • helps 'by default' avoiding bad coupling between assemblies, and makes boo-generated assemblies less noisy on static analysis tools.
Show
Cedric Vivier added a comment - - edited Oh I do not suggest changing them 'private' (though that would be my preferred choice too, hence BOO-1091 ). 'internal' would actually be even more permissive than 'protected' within the same assembly. But I think this is a good tradeoff since it :
  • does not break anything, changing to private would obviously break a lot of code (and would make prototyping/subclassing 'harder')
  • allows quick prototyping (within the same assembly), sounds boo-ish to me.
  • does not, as currently, create 'by default' an unwanted/unnoticed/undesirable visible API usable by external code (this the main problem of current default imho)
  • helps 'by default' avoiding bad coupling between assemblies, and makes boo-generated assemblies less noisy on static analysis tools.
Hide
Cedric Vivier added a comment -

So, should we take the opportunity of 0.9 to make the change?

Show
Cedric Vivier added a comment - So, should we take the opportunity of 0.9 to make the change?
Hide
Rodrigo B. de Oliveira added a comment -

I think 'internal' is worse than 'protected'.

Show
Rodrigo B. de Oliveira added a comment - I think 'internal' is worse than 'protected'.
Hide
Cedric Vivier added a comment - - edited

Well 'worse' is relative depending you dislike/fear more internal bad coupling than external/third-party bad coupling, but I get your objection.

Any chance we could then be more 'disruptive' and directly changing to 'private' ?
As Avish suspected I'm not holding my breath about it ( ) and am not sure it's worth the 'breakage', but well, since now is a good time if we ever decide to do this, it's the moment to ask.

Although there is BOO-1091 to workaround this when one prefer other defaults, maybe we could add a "--strict" compiler option that is more conservative on this kind of things (I think we discussed some time ago about such a potential "strict" mode for other things as well [1]).
What do you think?

1:

  • minimum visibility by default (like C#)
  • API-related types must be explicitely declared (method parameters + return types) [suggested by Daniel and Oren/Ayende on the list, and I like it too (especially for visible methods, I do this all the time it makes code more solid and easier to read/grep imo, so having the compiler to enforce this in strict mode sounds good to me)]
  • more?
Show
Cedric Vivier added a comment - - edited Well 'worse' is relative depending you dislike/fear more internal bad coupling than external/third-party bad coupling, but I get your objection. Any chance we could then be more 'disruptive' and directly changing to 'private' ? As Avish suspected I'm not holding my breath about it ( ) and am not sure it's worth the 'breakage', but well, since now is a good time if we ever decide to do this, it's the moment to ask. Although there is BOO-1091 to workaround this when one prefer other defaults, maybe we could add a "--strict" compiler option that is more conservative on this kind of things (I think we discussed some time ago about such a potential "strict" mode for other things as well [1]). What do you think? 1:
  • minimum visibility by default (like C#)
  • API-related types must be explicitely declared (method parameters + return types) [suggested by Daniel and Oren/Ayende on the list, and I like it too (especially for visible methods, I do this all the time it makes code more solid and easier to read/grep imo, so having the compiler to enforce this in strict mode sounds good to me)]
  • more?
Hide
Rodrigo B. de Oliveira added a comment - - edited

The main issue I see right now is that such a change could silently change behavior. The following compiles without errors no matter if the 'i' field is protected or private:

class Base:
	i = 0
	
	virtual def foo():
		print i
	
class E(Base):
	def foo():
		i = 42
		print i

And the programs are not equivalent.

That should give an error if 'i' is private.

Show
Rodrigo B. de Oliveira added a comment - - edited The main issue I see right now is that such a change could silently change behavior. The following compiles without errors no matter if the 'i' field is protected or private:
class Base:
	i = 0
	
	virtual def foo():
		print i
	
class E(Base):
	def foo():
		i = 42
		print i
And the programs are not equivalent. That should give an error if 'i' is private.
Hide
Cedric Vivier added a comment - - edited

Hmm yeah so we cannot change it ever now
Well interestingly I just thought about another alternative (that made me discover BOO-1114) : "protected internal"
(which would not change behavior in your example above, but sadly would for external assemblies using a default protected field - I'm not sure it is very common out there but it's still silent breakage)

Are you ok with the --strict compiler option? Any idea for another default that could be more conservative?

Show
Cedric Vivier added a comment - - edited Hmm yeah so we cannot change it ever now Well interestingly I just thought about another alternative (that made me discover BOO-1114) : "protected internal" (which would not change behavior in your example above, but sadly would for external assemblies using a default protected field - I'm not sure it is very common out there but it's still silent breakage) Are you ok with the --strict compiler option? Any idea for another default that could be more conservative?
Hide
Daniel Grunwald added a comment - - edited

In my opinion, a "--strict" option should not allow implicit variable declarations. We'd need some keyword to explicitly declare a variable without having to specify its type. Like "Option Explicit On" in VB.
I realize this is a large change to Boo, but it's not a good idea to silently change field assignments to variable declarations just because someone changed the base class.
So private could be the default in strict mode, and Rodrigo's 'i = 42' example would be a compiler error.

And also something like "Option Strict On" in VB is necessary: disable implicit downcasts.
Currently it's possible to call a method with the signature 'def Method(a as object, b as string)' with 'Method(aString, anObject)' and you get no compilation error/warning, only an InvalidCastException at runtime.

Show
Daniel Grunwald added a comment - - edited In my opinion, a "--strict" option should not allow implicit variable declarations. We'd need some keyword to explicitly declare a variable without having to specify its type. Like "Option Explicit On" in VB. I realize this is a large change to Boo, but it's not a good idea to silently change field assignments to variable declarations just because someone changed the base class. So private could be the default in strict mode, and Rodrigo's 'i = 42' example would be a compiler error. And also something like "Option Strict On" in VB is necessary: disable implicit downcasts. Currently it's possible to call a method with the signature 'def Method(a as object, b as string)' with 'Method(aString, anObject)' and you get no compilation error/warning, only an InvalidCastException at runtime.
Hide
Cedric Vivier added a comment - - edited

>We'd need some keyword to explicitly declare a variable without having to specify its type.
>I realize this is a large change to Boo, but it's not a good idea to silently change field assignments to variable declarations just because someone changed the base class.

A way to do this change without too much work, and more importantly without introducing a new keyword (which would make --strict mode quite impractical imo) would be to enforce naming of fields with _ prefix like recommended in Boo documentation, and disallow _ prefix for variables.
This way in strict mode this kind of behavior change because of base class change would not be able to happen
And this would work as-is for existing code which has been following the style recommandation (quite a lot actually if I'm not mistaken)

Show
Cedric Vivier added a comment - - edited >We'd need some keyword to explicitly declare a variable without having to specify its type. >I realize this is a large change to Boo, but it's not a good idea to silently change field assignments to variable declarations just because someone changed the base class. A way to do this change without too much work, and more importantly without introducing a new keyword (which would make --strict mode quite impractical imo) would be to enforce naming of fields with _ prefix like recommended in Boo documentation, and disallow _ prefix for variables. This way in strict mode this kind of behavior change because of base class change would not be able to happen And this would work as-is for existing code which has been following the style recommandation (quite a lot actually if I'm not mistaken)
Hide
Cedric Vivier added a comment -

Won't fix since it is too breaking.
Can do it through Strict Mode (BOO-1115) or pragma (BOO-1125).

Show
Cedric Vivier added a comment - Won't fix since it is too breaking. Can do it through Strict Mode (BOO-1115) or pragma (BOO-1125).

People

Vote (0)
Watch (0)

Dates

  • Created:
    Updated:
    Resolved: