Given the following line
cat.meow(10, x);
"meow" is the "function" or "method" being called
10 is the "first argument"
x is the "second argument"
What is cat called?
I'm dissatisfied with the answer, cat is called "the object". I want to say I've heard it called the "receiver", but I don't remember where I've heard that.
Considering both 10 and x can be objects, calling cat "the object" doesn't help me distinguish this component from the argument components.
This makes it difficult to discuss the various components that makeup a function call.
It is called the “subject” following the subject-verb-object sentence structure that object-oriented programming mimics:
cat.meow(10, x);
|_||___||_____|
| | |
| | +--> object (the arguments list is a tuple object)
| |
| +--> verb (the verb is the method name with the dot)
|
+--> subject (quite self explanatory)
I should clarify that I call it the “subject” because it makes sense to me. However, there's no consensus on this nomenclature. Everyone has their own opinions on what it should be called.
An object is an instance of a specific class. You can use it to say cat is an instance of class [put class name here], just like 10 is an instance of Integer.
Normally we call that object. According to your logic, take it in this way
meow(self,10, x) - This is the actual function where self is an object like 10 and x
Same in this case - cat.meow(10,x)
Related
I'm working on a custom interpreter for fun ;)
What I have so far is assigning variables, defining and calling functions, arrays, loops, if blocks etc...
I've started adding OOP elements to my language and I'm having trouble implementing the "this" / "self" keyword.
I just cannot figure out a solution to this problem.
I've thought about a few solutions:
a class stores it's instances (as a dictionary) and when the "this" keyword appears, the interpreter ignores "private" and "public" keywords (to call a private method from a public one), creates a call to the method referenced by "this" and returns.
the "this" keyword is a reference which under the hood is the instance itself, but the method access modifiers are dropped for that call. this is similar to the first one, but I cannot think of anything better.
Also it would be nice if you knew C# (primarly) or C++, since I'm heavily relying on OOP to create my interpreter.
heres a small sample of code that I would like to implement:
struct Dog has
pub prop age;
prv def bark() do
println "woof woof";
end
pub def run(dist) do
loop 0 to $dist with "d" do
println ("the dog ran " + string $d) + " meters";
$self.bark();
end
end
end
def main(args) do
new Dog -> $dog;
7 -> $dog.age;
println $dog.age;
$dog.run 30;
end
notice that the bark() method is "prv" (private). I would like to know how can I make the struct be aware of it's instances so I can make the dog bark each time it runs (calling a private method from a public method).
Thanks in advance
Your interpreter is going to need to keep an execution stack and environment (otherwise you wouldn't know where to return to after a method is finished, etc.).
In this execution stack/env, apart from a function pointer/signature, you'd also keep the object the method is being invoked on (if any, remember about static-like functions).
This reference that you'd store would then be also accessed when de-referencing $this. And actually this is both part 1 and 2 of your idea - you could put some kind of checks like visibility of methods etc. there.
Good luck, sounds like a fun project!
My script grammar contains the following:
if_statement
: IF condition_block (ELSE IF condition_block)* (ELSE statement_block)?
;
condition_block
: expression statement_block
;
expression
: expression op=(LTEQ | GTEQ | LT | GT) expression #relationalExpression
| expression op=(EQ | NEQ) expression #equalityExpression
| expression AND expression #andExpression
| expression OR expression #orExpression
| atom #atomExpression
;
atom
: OPAR expression CPAR #parenExpression
| INT #numberAtom
| (TRUE | FALSE) #booleanAtom
| STRING #stringAtom
;
What I would like to do, is to make sure that the user doesn't compare e.g. an INT to a STRING.
I use a Listener to provide errors to the user when they create a script. So what I want to do is something like
public override void EnterRelationalExpression([NotNull] ScriptEvaluatorParser.RelationalExpressionContext context)
{
<..compare context.expression(0) to context.expression(1) here
and add an error if not the same base type...>
base.EnterRelationalExpression(context);
}
Doing this in a Visitor is easy
object left = Visit(context.expression(0)
object right = Visit(context.expression(1)
<...compare types...>
But how do I do the same in the Listener? I can new up a Visitor and do it that way, but I was wondering if there is a better way to do the check without having to new up a Visitor.
I’ve done this before by adding a type stack to my listener.
I use the exit*() listener hooks (you can’t really have any useful information about children in the enter*() methods, as the children have not been visited.
As an expression is exited, I can determine the type directly, if it’s a simple type (or looking it’s type up in a symbol table if it’s an identifier). Then push the type on the type stack. For expressions like you equalityExpression, I pop the top two items from the type stack and check their compatibility (of course, it then pushes a boolean type on the type stack.
For and and or expressions, just pop the top two items, ensure they’re boolean and then push boolean.
This does depend on having a symbol table available to resolve identifier types, and is a bit of a work-around for listeners not returning values, but it has worked well for me. I like the visitor handling the navigation and ensuring all nodes are visited. But, as Bart mentions, if you’re comfortable with using visitors to accomplish this, there’s not really one way that’s “better” than another.
You can also look into adding locals to your rules to hold that resulting type. This avoids the need for a type stack, and the management of that stack, but makes your grammar target language specific (which I like to avoid). You’d still need to leverage the exit*() methods since children would have to be visited before the locals were populated (BTW, locals are just a way of adding additional fields to the ParseTreeContext for nodes.)
When I make a class method that starts with a ^, and I try to invoke it, it gives me an error.
class C {
method ^test () {
"Hi"
}
}
dd C.new.test;
Too many positionals passed; expected 1 argument but got 2
in method test at .code.tio line 1
in block <unit> at .code.tio line 1
If I make the same method without a leading ^, it works fine.
class C {
method test () {
"Hi"
}
}
dd C.new.test;
"Hi"
I've seen modules expose classes with methods that do start with a ^, which leads to my question. Why am I getting this error when I define a method name that starts with a ^?
TL;DR The method is getting invoked properly. The ^ in foo.^bar indicates a "metamethod". This is neither an instance method nor a class method. Metamethods are passed both an invocant, as is the case for all methods, and another "original invocant" object as the first argument.
Most users will never need to think about this stuff. But you've asked, so let's dig in...
Metamethods
Quoting the Meta-object protocol (MOP) Raku doc page:
Raku is built on a meta object layer.
This MOP layer defines various built in "metamethods" that you can use.
For example:
say .^attributes given class bar { has Int $!foo }
This displays (Int $!foo). The .^attributes method call is a metamethod. It's called on the (typically invisible) metaobject that determines how a Raku type works behind the scenes. In this case, it returns the attributes (has variables) of a class.
But there can also be user defined metamethods. One way to declare these is in an otherwise ordinary class:
class {
has Int $!foo;
method ^attributes ($arg) { self, $arg }
}
say baz.^attributes
The above baz class includes an ^attributes metamethod declaration that overrides the built in metamethod. Of special note, I've added an argument. ALL metamethods get at least one argument (in addition to a regular invocant).
With this declaration, instead of (Int $!foo) in response to an .^attributes call you instead get the list self, $arg from the .^attributes method in the baz class.
Note how self is neither a baz instance object nor a baz type object -- instead it's Perl6::Metamodel::ClassHOW+{<anon>}.new -- whereas $arg is a baz (type) object.
The rest of this answer explains what's going on in more detail.
A recap of an ordinary method call
First, let's recap a typical method call.
The syntax foo.bar results in a "bar" method (message) being dispatched to foo.
If foo is an instance of a class, "bar" is dispatched to that instance. Such a method call is sometimes referred to as an "instance method".
If foo is a type object corresponding to a class, "bar" is dispatched to that type object. Such a method call is sometimes referred to as a "class method".
In both cases, "bar" is dispatched to foo.
#foo.^bar
The syntax foo.^bar is different.
Read the ^ as pointing up to another object that hovers invisibly above foo, or indeed anything related to the kind of type foo is.
Such objects are HOW objects that determine How Objects Work. These HOW objects typically stay invisible, making things work nicely, with users blissfully unaware of their existence and the work they're doing.1
A method call of the form foo.^bar ordinarily results in Raku dispatching a metamethod call to foo's HOW object.
These metamethods require two invocant-like arguments. There's the HOW object. This is passed as the regular invocant. Then there's the foo object. This is passed as a first ordinary argument to the metamethod.
So that's what ordinarily happens when you call foo.^bar -- a metamethod call is dispatched to foo's HOW object and foo is passed as an ordinary argument storing what could be said to be "the original invocant".
#foo.^bar when there's no built in .^bar metamethod
If you call foo.^bar when there's no such method you'll get an error:
42.^bar
yields:
No such method 'bar' for invocant of type 'Perl6::Metamodel::ClassHOW'
Note how the invocant type is a metamodel class, not 42 or Int.
If a user defined class declares a ^.bar, then Raku calls it, passing the instance/class's HOW object as the invocant and the "original invocant" (foo) as the first ordinary argument:
class foo {
method ^bar ($arg) { self, $arg }
}
say foo.^bar; # (Perl6::Metamodel::ClassHOW+{<anon>}.new (foo))
Footnotes
1 Calling .HOW on an object returns its HOW:
say .HOW given class {} # Perl6::Metamodel::ClassHOW
HOW objects are part of the MOP, a layer deep down inside Raku.
Most devs will never need to explicitly dig down to this level.
If you dig even deeper you're leaving specified Raku. In Rakudo the .HOW of a HOW object is typically an NQP object:
say ((.HOW.new given class {}).HOW).^name; # NQPClassHOW
I am new to the programming language Smalltalk and I can't seem to figure out how to call a method with arguments. I've been playing around with some code and created some methods, like for example (in GNU Smalltalk):
bin: n num: k [
| i |
i := 1.
1 to:k do:[:j|
i := i * 2.
].
^i
]
I would now like to call this function and actually get an answer, like for example: bin: 4 num: 2 (don't know how to do this). How can I do that? Is it even right to write 'bin: n num: k' when creating a method like I have done?
Thanks in advance!
First, you need a receiver object, on which you want to invoke that method. You did not indicate in which class you have created your method, so I will just assume that you called it MyClass.
| myObject |
myObject := MyClass new.
Then you can send that message to (invoke that method on) myObject like this:
myObject bin: 4 num: 2
So you just write the message send (which will invoke the method) after the receiver.
I have a CtMethod instance, but I don't know how to get names of parameters (not types) from it. I tried getParameterTypes, but it seems it returns only types.
I'm assuming it's possible, because libraries I'm using don't have sources, just class files and I can see names of method parameters in IDE.
It is indeed possible to retrieve arguments' names, but only if the code has been compiled with debug symbols otherwise you won't be able to do it.
To retrieve this information you have to access the method's local variable table. For further information about this data structure I suggest you to check section 4.7.13. The LocalVariableTable Attribute of the jvm spec. As I usually say, JVM spec may look bulky but it's an invaluable friend when you're working at this level!
Accessing the local variable table attribute of your ctmethod
CtMethod method = .....;
MethodInfo methodInfo = method.getMethodInfo();
LocalVariableAttribute table = methodInfo.getCodeAttribute().getAttribute(javassist.bytecode.LocalVariableAttribute.tag);
You now have the the local variable attribute selected in table variable.
Detecting the number of localVariables
int numberOfLocalVariables = table.tableLenght();
Now keep in mind two things regarding the number in numberOfLocalVariables:
1st: local variables defined inside your method's body will also be accounted in tableLength();
2nd: if you're in a non static method so will be this variable.
The order of your local variable table will be something like:
|this (if non static) | arg1 | arg2 | ... | argN | var1 | ... | varN|
Retriving the argument name
Now if you want to retrieve, for example, the arg2's name from the previous example, it's the 3rd position in the array. Hence you do the following:
// remember it's an array so it starts in 0, meaning if you want position 3 => use index 2
int frameWithNameAtConstantPool = table.nameIndex(2);
String variableName = methodInfo.getConstPool().getUtf8Info(frameAtConstantPool)
You now have your variable's name in variableName.
Side Note: I've taken you through the scenic route so you could learn a bit more about Java (and javassists) internals. But there are already tools that do this kind of operations for you, I can remember at least one by name called paranamer. You might want to give a look at that too.
Hope it helped!
If you don't actually want the names of the parameters, but just want to be able to access them, you can use "$1, $2, ..." as seen in this tutorial.
It works with Javaassist 3.18.2 (and later, at least up to 3.19 anyway) if you cast, like so:
LocalVariableAttribute nameTable = (LocalVariableAttribute)methodInfo.getCodeAttribute().getAttribute(LocalVariableAttribute.tag);