Generic Messages are an implementation of Generic Functions known from CLOS. They add support to dispatch a method on multiple parameters instead of a dispatch based on the receiver. They were implemented during the seminar Programming Languages - Implementation and Design at the chair @hpi-swa-teaching at the HPI, Potsdam, Germany.
Make sure that you have Metacello installed.
- Clone this repo.
- Open your Monticello Browser inside your Squeak
- Add a filetree repository to your package and select path: {repo_home}/packages
- Load GenericFunctions-Core, GenericFunctions-Exceptions and GenericFunctions-Tools (Other packages aren't important for running Generic Messages. They contain tests or course related stuff like a Gamada grammar)
- You're ready to go!
- Open the GenericMessageBrowser by evaluating
GenericMessageBrowser open
- Create a new class
Object subclass: #DemoIntegerFive
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'GenericFunctions-Demo'
- Add a numericValue message to your demo integer
numericValue
^ 5
- Add your first MultiMethod. We want to define the MultiMethod #add: for a SmallInteger
add: anInteger
<MultiMethod>
<parameter: #anInteger isKindOf: #SmallInteger>
^ self numericValue + anInteger
- Then we define a MultiMethod wich handles an incoming float by converting it first
add: aFloat
<MultiMethod>
<parameter: #anInteger isKindOf: #Float>
^ self numericValue + aFloat asInteger
- Let's try out! Open up a workspace and evaluate the following commands
DemoInteger new add: 10 "returns 15"
DemoInteger new add: 12.4 "returns 17"
DemoInteger new add: 'Do not work yet' "throws an error"
- Add another class called DemoFloat and add the following MultiMethod
numericValue
^ 7.5
add: anInteger
<MultiMethod>
<parameter: #anInteger isKindOf: #SmallInteger>
^ self numericValue + anInteger asFloat
- That's it! You have implemented your first Generic Message with MultiMethods belonging to different classes. Feel free to explore the structure and inspect some elements like DemoFloat, DemoInteger, GenericMessage uniqueInstance, (GenericMessage uniqueInstance) at: #add:!
Generic Messages ship with their own system browser. Using that browser, called GenericMessageBrowser, you can browse, create and remove MultiMethods. You don't have to deal with creating GenericMessages or DiscriminatingMethods by hand. This browser is mandatory to properly register and unregister Generic Messages and Discriminating Methods when creating MultiMethods. The default system browser doesn't have that functionality and will break your setup!
The following actions can be performed without taking the system into a non-consistent state:
- You can add MultiMethods by annotating them with
<MultiMethod>
pragma - You can change existing MultiMethods
- You can specify parameters by providing a class symbol
- You can browse MultiMethods using the GenericMessageBrowser
- You can delete MultiMethods
- You can delete classes with MultiMethods
- You can use your Squeak like before. My code does not make any changes to existing code
The following actions can't be performed, because they are not implemented or take the system into a non-consistent state:
- You can't file out classes with MultiMethods
- You can't use Generic Messages inside the default system browser. Please refer to the tooling section
- You can't change instance variables of a class already containing MultiMethods. Recompiling logic is currently missing
- MethodCombinations and Ranking during dispatch isn't implemented yet. Therefore, dispatch fails if multiple methods are applicable
- You can't specify the specializing parameter. Pragmas are mapped from the left to right parameters. In addition, you can't specify a MultiMethod without any specializer.
Generic Messages are saved in a global dictionary, more precise: Inside the Smalltalk dictionary. Both DiscriminatingMethods and MultiMethods are stored beside CompiledMethods inside the methodDict of a class. DiscriminatingMethods have a 'normal' selector without any type annotations. They catch the message send of a receiver. MultiMethods have a selectior with type annotations. CompiledMethods aren't affected.
A sender sends a message to a class which belongs to a Generic Message. The message send is caught by the DiscriminatingMethod. The DiscriminatingMethod is now responsible for passing the arguments and the receiver to the GenericMessage, which will perform the dispatch. The GenericMessage is checking against all of it's MultiMethods if they are applicable for this set of arguments. Applicable methods are ranked and most specific method gets invoked. Generic Messages can be called directly, too. Then, there is no need for a DiscriminatingMethod.
Unfortunately, you can't rely on my testbed anymore. Due to side effects and a bad performing VM I stopped programming regarding the TDD paradigm. Some tests should work. On the other hand, some tests cause side effects because they to clean the method dicts and global Generic Message dict. If you want to be safe, skip importing GenericFunctions-Tests-*.
- Foote B., Johnson R.E., Noble J. (2005) Efficient Multimethods in a Single Dispatch Language. In: Black A.P. (eds) ECOOP 2005 - Object-Oriented Programming. ECOOP 2005. Lecture Notes in Computer Science, vol 3586. Springer, Berlin, Heidelberg
- REIN, Patrick. Automatic Reuse through Implied Methods: The Design and Implementation of an Abstraction Mechanism for Implied Interfaces. In: Companion to the first International Conference on the Art, Science and Engineering of Programming. ACM, 2017. S. 38.
- REIN, Patrick. Deducing classes: integrating the domain models of object-oriented applications. In: Companion Proceedings of the 2016 ACM SIGPLAN International Conference on Systems, Programming, Languages and Applications: Software for Humanity. ACM, 2016. S. 67-68.
- DEMICHIEL, Linda G.; GABRIEL, Richard P. The Common Lisp Object System: An Overview. In: ECOOP. 1987. S. 151-170. BOBROW, Daniel G., et al. CommonLoops: Merging Lisp and object-oriented programming. In: ACM Sigplan Notices. ACM, 1986. S. 17-29.
- GOLDBERG, Adele; ROBSON, David. Smalltalk-80: the language and its implementation. Addison-Wesley Longman Publishing Co., Inc., 1983.
- ROWLEDGE, Tim, et al. A Tour of the Squeak Object Engine. Squeak: Open Personal Computing and Multimedia. Prentice Hall, 2001.
- SAMIMI, Hesam, et al. Call by meaning. In: Proceedings of the 2014 ACM International Symposium on New Ideas, New Paradigms, and Reflections on Programming & Software. ACM, 2014. S. 11-28.
- FOOTE, Brian; JOHNSON, Ralph; NOBLE, James. Efficient multimethods in a single dispatch language. ECOOP 2005-Object-Oriented Programming, 2005, S. 733-733.
- Wikipedia CLOS
- Differences between Polymorphism and Overloading
- Differences between early and late binding
- Swindle, a CLOS implementation in Lisp