Hi,

>From Bug #20900/ PR 1818 it looked like it is not really clear on how to 
>"deprecate" correctly. Therefore I summarized and
wrote a short guide following what we contributors used as best practice so 
far. Also read [1], [2] and [3] and check some of the 
deprecation settings in the Pharo settings browser. Just open SettingsBrowser 
and search for "Depre".

I write this mail to "pharo-dev" with CC: "pharo-users" list - because of 
common interest. But comments and replies should
please go to "pharo-dev" so we do not disrupt the thread too much. Thanks!

Please review what I wrote and ideally we can put the text or a link to it as 
"Deprecation guide" into the documentation
 / wiki / ... on GitHub afterwards.

Hope this helps a little bit.

Thanks
T.

[1] https://en.wikipedia.org/wiki/Deprecation
[2] 
https://www.peteruhnak.com/blog/2015/08/06/transforming-deprecated-code-with-rewritetool/
[3] 
https://pharoweekly.wordpress.com/2016/06/17/automatic-deprecation-refactoring/

------------------------------------------------------------------------------------------------------------------------------
In any Pharo version we have a special package hosting deprecated methods and 
classes. This allows smooth migration for Pharo users
as code should still load and runs to some extent - but deprecation warnings 
and possibly a helping hand (in form of automatic
code transformations) could be given to support migration.

As we currently work on Pharo7 there is a "Deprecated70" package in the image 
hosting deprecated methods and classes intended to be
removed for Pharo 8. When Pharo 7 is released the users can easily spot the 
deprecations - also because they are striked through
(more on this below). When Pharo 8 iteration starts the "Deprecated70" will be 
replaced with an empty "Deprecated80" package.


DEPRECATING METHODS
===================   

   If you deprecate a METHOD use #deprecated: message and switch it to be an 
extension method in *Deprecated70*. If the 
   method could be replaced by calling another method then dispatch the call to 
the new method and ideally provide a transformation
   so next time the old method is called the sender method is automagically 
rewritten and could be adopted/migrated:

        oldMethod 
        "An old method we do not use anymore. But luckily there is a 
replacement."              

            self deprecated: 'Please use #newMethod instead'
              transformWith: '`@receiver oldMethod' -> '`@receiver newMethod'.

            ^ self newMethod

    So if there is a method like 

       foo
         self oldMethod 

    sending the old deprecated method it will be migrated to

       foo
         self newMethod 

    as soon as foo, the oldMethod and the transformation is called. If the 
automatically migrated method is under version
    control (Monticello or git) you will easily see that #foo was modified.

    In case there is no replacement for a method you would like to deprecate 
then it is best to throw an error when it is used:

        veryOldMethod 
           "A very old method hopefully nobody uses. So we do no provide a 
replacement."                

            self deprecated: 'The method #veryOldMethod is deprecated without 
any replacement'.

           ^ self error: 'Do not use #veryOldMethod anymore'

    Note that the method is striked through in the Pharo system browser in both 
cases to show that it should not be used anymore.

    In the standard image calling a deprecated method is logged on the 
Transcript and flagged with a warning dialog. This should
    help users and maintainers of external packages to easily spot when they 
still use deprecated code.
    You can change these settings in Pharo Settings Browser under Tools -> 
Debugging -> Deprecation Handling.

DEPRECATING CLASSES
===================

   If you deprecate a CLASS implement #isDeprecated on class side to return 
true and move it to package "Deprecated70"
   Ideally write in the class comment why it is deprecated and if there is a 
replacement class what to use instead

        Object subclass: #OldClass
                instanceVariableNames: ''
                classVariableNames: ''
                package: 'Deprecated70-OldTag'

    and comment to explain the reasons:

         OldClass comment: 'Use NewClass instead'.  

    and implement in class side method category 'testing'  
     
       isDeprecated
          "We do not need this class anymore"
          ^true

    Note that the class is striked through in the system browser.


DEPRECATING PACKAGES
====================

   If you deprecate a PACKAGE then rename it with "Deprecated" in the name. Let 
the class side of the package manifest 
   (typically a subclass of PackageManifest within the package) als return 
#isDeprecated with true. In the class
   comment of the package manifest (which also serves as package comment) 
explain why the package is deprecated and
   if there is a replacement or not.
   
   Example: your package name is "OldPackage-Core", so the new name is 
"OldPackage-Deprecated-Core". Create a manifest
            or use the existing one. A Manifest should be a subclass of 
PackageManifest and should be categorized within
            a 'Manifest' tag.

        PackageManifest subclass: #ManifestOldPackageCore
            instanceVariableNames: ''
            classVariableNames: ''
            package: 'OldPackage-Deprecated-Core-Manifest'

    and comment to explain the reasons:

        ManifestOldPackageCore comment: 'This package is not useful anymore. 
Check NewPackage for replacement'.

    and implement in class side method category 'testing'  
     
       isDeprecated
          "We do not need this package anymore"
          ^true

    Note that the manifest class and the package is striked through in the 
system browser. Be aware that a deprecated
    package might be removed completely already in the next Pharo major version 
iteration.


Reply via email to