How do I list all unimplemented methods in a package? Given that the method should be implemented in that package and not in other (for example in a superclass outside the package or in Object).
Edit: Yes, I'd like to know "messages sent that are not implemented" but to limit the analysis to one specific given package, for ex:
FooPackage unimplementedMessageSends.
I haven't fully tested this so you might need to tweak it a bit to suit your requirements, but from how I understand your question, you might be after something like this:
| allMethodsSent allMethodsImplemented |
allMethodsSent := IdentitySet new.
allMethodsImplemented := IdentitySet new.
(SystemOrganization listAtCategoryNamed: #'Collections-Arrayed')
do: [:eachClassName |
(Smalltalk at: eachClassName) methodDictionary valuesDo: [:eachMethod |
allMethodsSent addAll: eachMethod messages.
].
allMethodsImplemented addAll: (Smalltalk at: eachClassName) selectors
].
^allMethodsSent
removeAllFoundIn: allMethodsImplemented;
yourself
Hopefully that'll help you get started at least, if you need to tweak it, have a look at the classes Behavior (to see what you can use, not to change it!), CompiledMethod, and SystemOrganization.
Obviously this example uses the category (I'm assuming that's what you mean by package?) "Collections-Arrayed", but you could of course adapt it to make that a method parameter, something like:
MyUtilClass unimplementedMessageSendsFor: aCategorySymbol
Related
From the docs that say,
Returns the self-reference to the instance itself:
my $b; # defaults to Any
say $b.serial.^name; # OUTPUT: «Any»
my $breakfast = 'food';
$breakfast.serial.say; # OUTPUT: «food»
I do not have the foggiest what this routine does, please can someone explain?
On Supplys, it is an informational method that is supposed to indicate whether there will never be any concurrent emit on that Supply.
On HyperSeq and RaceSeq, it returns a serialized Seq, so you could consider it the opposite of the hyper and race method.
In general, it appears to return itself, which seems to make sense from the HyperSeq and RaceSeq point of view.
And yes, these should be documented properly, so please create a documentation issue. Thank you!
In the doc example it does nothing. That is, if you remove it you get the same results:
my $b; # defaults to Any
say $b.^name; # OUTPUT: «Any»
my $breakfast = 'food';
$breakfast.say; # OUTPUT: «food»
More generally, I think you'd best ignore the serial method other than to open a doc issue pointing to this SO if you'd like to improve the doc.
The serial method does not appear to be in the official language
A search of the roast repo for "serial" yields zero matches.
Within Rakudo source code the method name serial has been overloaded to have one of three meanings:
A boolean declaring whether a Supply sequence is always serial. Rakudo source examples: 1, 2. This looks to me like an internal method that doesn't need to be documented.
A coercion of parallel sequence (hyper or race) to a serial version of the same sequence. This looks to me like an internal method that doesn't need to be documented.
A "no op" that returns its invocant. I suspect it would be best if it were not documented, at least until such time as its raison d'etre is clear; its official status viz-a-viz the spec (roast) is clear; and/or there's an attempt to systematically document which operations have the is nodal set on them.
None of the above seems to warrant ordinary users' attention or documentation.
The Any class definition of a serial method seems pointless
The Any class serial method returns self, i.e. when called it is a no op.
I don't currently understand why there is an Any class definition.
One possible point for it would be that there are .serial calls made by internal code on instances of an unknown and generally unknowable class and there thus needs to be a default definition of serial in the Any class.
But a search of the rakudo repo for ".serial" suggests that calls are only made to supplies or hyper/race seqs.
That said, I note the is nodal trait on the proto serial declaration in Any that immediately precedes the multi method serial declaration. Perhaps that is the reason it's in Any.
See also Arbitrary drift of methods to Mu and Any.
The documentation you quoted seems pointless
The definition and example seem to reflect someone's sense of humor. I applaud use of humor but in this case I suspect the best improvement would be to just remove the page you linked.
In Smalltalk (and specifically Pharo/Squeak) I want to know if it is OK to leave out the "[" and "]" for the argument to messages like at:ifAbsent: if you don't need a block, like this;
^ bookTitles at: bookID ifAbsent: ''.
and
^ books at: bookID ifAbsent: nil.
the code works because (in Pharo/Squeak) Object>>value just returns self. But I want to know how accepted this use is or if you should always type the [ and ] even when you don't care if the argument is evaluated quickly or more than once.
The signature:
at: key ifAbsent: aBlock
declares an intention of using a block as a 2nd parameter...
But Smalltalk is not a strongly typed language, so, what kind of objects can you pass there? any kind that understand the message #value, so, be careful about each particular meaning of #value in each case, but take advantages of polymorphism!
Not all Smalltalk dialects implement #value on Object out of the box, so your code might not run on other Smalltalk dialects, IF you hand in an object that does not understand #value.
It is okay to pass objects of whatever kind as long as you know that what #value does is what you expect,
Your code may look strange to people who come from other smalltalk dialects or are new to Smalltallk, because they learned that what you pass in here is a Block, but so does sending messages like #join: to a Collection of Strings...
In the end, I'd say don't worry if portability is not a major issue to you.
This is what Pharo’s Code Critics say about similar situations:
Non-blocks in special messages:
Checks for methods that don't use blocks in the special messages.
People new to Smalltalk might write code such as: "aBoolean ifTrue:
(self doSomething)" instead of the correct version: "aBoolean ifTrue:
[self doSomething]". Even if these pieces of code could be correct,
they cannot be optimized by the compiler.
This rule can be found in Optimization, so you could probably ignore it, but i think it is nicer anyway to use a block.
Update:
at:ifAbsent: is not triggered by this rule. And it is not optimized by the compiler. So optimization is no reason to use blocks in this case.
I would say that it is not a good idea to leave them out. The argument will be evaluated eagerly if you leave out the parens, and will be sent #value. So if "slef doSomething" has side-effects, that would be bad. It could also be bad if #value does something you don't expect e.g. the perhaps contrived
bookTitles at: bookID ifAbsent: 'Missing title' -> 'ISBN-000000'
If your code works and you are the only person to view the source, then its ok. If others are to view the source then I would say a empty block [] would have been more readable. But generally speaking if you really care about bugs its a good idea not to venture outside standard practices because there is no way to guarantee that you wont have any problem.
I wasn't aware this syntax was valid.
+ (void) methodName:(TypeObject *)typeObject1:(TypeObject *)typeObject2;
Which is then called like so:
[object methodName:obj1:obj2];
I find it ugly and disturbing, but it builds.
Can someone point me at a reference which explains why this is valid.
FWIW the codebase (inherited) that this comes from, is rife with sloppy, lazy stuff, dozens of spelling errors and looks like it was formatted by someone with no need to ever read it again. (Thank you again uncrustify.)
This is a well-kown and documented feature (pdf, p. 14)
In principle, a Rectangle class could instead implement a setOrigin::
method with no label for the second parameter, which would be invoked
as follows:
[myRectangle setOrigin:30.0 :50.0]; // This is a bad example of multiple parameters
but apple discourage everbody of using parameter passing without keyword:
Use keywords before all arguments.
- (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag; -> Right.
- (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag; -> Wrong.
Why it was allowed by the creators of objective-C, I dont know. Maybe it has to do with the Smalltalk heritage.
This relates to the Dolphin variant of Smalltalk.
I'm digging around in the image to try and figure this out but haven't
find the correct method invocation yet and I'm hoping someone might be
able to help shortcut this process. What I'm trying to do is to find
all methods (either within the entire system or, preferably, just
within a single class) which refer to a given string, symbol, or
method. I've found the #references family of methods in
SmalltalkSystem but have not had luck figuring out how to get them to
give back something resembling what I want.
The programmatic way, here we go
SmalltalkSystem current browseContainingText: 'Dolphin'.
I don't have Dolphin at hand, but the following code should work in all Smalltalk with the refactoring engine (this includes Dolphin):
result := BrowserEnvironment new matches: 'Dolphin'.
Then you can iterate over the results like this:
result classesAndSelectorsDo: [ :class :selector | ... ].
I have a class and I want to change the name of a specific method in run time.
I guess there's a method in the 'Behavior' class that does it. But I just can't find it. any help? [in squeak]
The normal way a user does this is to modify the method source and 'accept it' then delete the old version. So it's not likely that basic Squeak includes a single method to do this, although I could be wrong.
However if you install, for example, OmniBrowser there is a method refactoring called 'rename' and you could inspect and find code to perform this refactoring. It is fairly complex, firstly because the refactorings are done using the command pattern which involves a little redirection to work out, but secondly because this is a fairly complex refactoring which includes modifying the call sites.
What you are suggesting puts HUGE red flags up for me.
What is it you are trying to accomplish with this?
Do you mean you want to change the name of the method you are calling at runtime?
If so, that's easy.
do something like:
|methodName|
methodName := self useMethod1 ifTrue: [#method1 ] ifFalse:[ #method2 ].
self perform: methodName.
You best use a refactoring
r := RenameMethodRefactoring
renameMethod: #foo:foo:
in: Foo
to: #bar:bar:
permutation: (1 to: #foo:foo: numArgs).
r execute.
Avoid voodoo magic in real code when possible.
That being said you can do some very interesting things by manipulating methods dynamically.
For instance the code bricks in Etoys are translated into Smalltalk methods. Other DSL implementations can also benefit from similar metaprogramming tricks.
After experimenting a bit I came up with the following code for renaming unary methods:
renameMethod: oldMethod inClass: class to: newMethod
| oldSelector newSelector source parser |
oldSelector := oldMethod asSymbol.
newSelector := newMethod asSymbol.
oldSelector = newSelector ifTrue: [^self].
"Get method category"
category := (LocatedMethod location: class selector: oldSelector) category.
"Get method source code"
source := class sourceCodeAt: oldSelector.
"Replace selector in method source"
(parser := class parserClass new) parseSelector: source.
source := (newSelector asString), (source allButFirst: parser endOfLastToken).
"Compile modified source"
class compile: source classified: category.
"Remove old selector"
class removeSelector: oldSelector
You could probably find an easier way to do this if you browse through the Squeak code a bit longer than I did.
You can't change a method's name, really, because it doesn't have one.
An object's method dictionary maps Symbols to CompiledMethods. "Change the name of a method" means "move the CompiledMethod value from this key to that key".