Is there a hook for when anonymous classes are assigned to a constant? - ruby

I've been practicing some Ruby meta-programming recently, and was wondering about assigning anonymous classes to constants.
In Ruby, it is possible to create an anonymous class as follows:
anonymous_class = Class.new # => #<Class:0x007f9c5afb21d0>
New instances of this class can be created:
an_instance = anonymous_class.new # => #<#<Class:0x007f9c5afb21d0>:0x007f9c5afb0330>
Now, when the anonymous class is assigned to a constant, the class now has a proper name:
Foo = anonymous_class # => Foo
And the previously created instance is now also an instance of that class:
an_instance # => #<Foo:0x007f9c5afb0330>
My question: Is there a hook method for the moment when an anonymous class is assigned to a constant?
There are many hooks methods in Ruby, but I couldn't find this one.

Let's take a look at how constant assignment works internally. The code that follows is extracted from a source tarball of ruby-1.9.3-p0. First we look at the definition of the VM instruction setconstant (which is used to assign constants):
# /insns.def, line 239
DEFINE_INSN
setconstant
(ID id)
(VALUE val, VALUE cbase)
()
{
vm_check_if_namespace(cbase);
rb_const_set(cbase, id, val);
INC_VM_STATE_VERSION();
}
No chance to place a hook in vm_check_if_namespace or INC_VM_STATE_VERSION here. So we look at rb_const_set (variable.c:1886), the function that is called everytime a constant is assigned:
# /variable.c, line 1886
void
rb_const_set(VALUE klass, ID id, VALUE val)
{
rb_const_entry_t *ce;
VALUE visibility = CONST_PUBLIC;
# ...
check_before_mod_set(klass, id, val, "constant");
if (!RCLASS_CONST_TBL(klass)) {
RCLASS_CONST_TBL(klass) = st_init_numtable();
}
else {
# [snip], won't be called on first assignment
}
rb_vm_change_state();
ce = ALLOC(rb_const_entry_t);
ce->flag = (rb_const_flag_t)visibility;
ce->value = val;
st_insert(RCLASS_CONST_TBL(klass), (st_data_t)id, (st_data_t)ce);
}
I removed all the code that was not even called the first time a constant was assigned inside a module. I then looked into all the functions called by this one and didn't find a single point where we could place a hook from Ruby code. This means the hard truth is, unless I missed something, that there is no way to hook a constant assignment (at least in MRI).
Update
To clarify: The anonymous class does not magically get a new name as soon as it is assigned (as noted correctly in Andrew's answer). Rather, the constant name along with the object ID of the class is stored in Ruby's internal constant lookup table. If, after that, the name of the class is requested, it can now be resolved to a proper name (and not just Class:0xXXXXXXXX...).
So the best you can do to react to this assignment is to check the name of the class in a loop of a background worker thread until it is non-nil (which is a huge waste of resources, IMHO).

Anonymous classes don't actually get their name when they're assigned to a constant. They actually get it when they're next asked what their name is.
I'll try to find a reference for this. Edit: Can't find one, sorry.

Related

Adding value to generic collection in class not allowed because of scope

I'm having trouble adding elements to an object that keeps a collection of generic-typed values. I tried a Minimal Working Example that causes the error:
class OneElementQueue {
type eltType;
var elements : [0..0] eltType;
//initializer
proc init(type eltType) {
this.eltType = eltType;
}
proc add(element : eltType) {
this.elements[0] = element;
}
proc remove() : eltType {
return this.elements[0];
}
} //end of OneElementQueue
class Monkey {
var name: string;
var age: int;
proc init(name : string, age : int) {
this.name = name;
this.age = age;
}
} //end of class Monkey
var q = new owned OneElementQueue(Monkey);
var m = new owned Monkey("Kyle", 6);
q.add(m);
When I try to compile all of this, I get an error:
$ chpl BadQueue.chpl
BadQueue.chpl:12: In function 'add':
BadQueue.chpl:13: error: Scoped variable would outlive the value it is set to
BadQueue.chpl:12: note: consider scope of element
$
What is the correct way to go about adding something to a generic data structure like this? How am I going about this the wrong way?
There are two possible approaches you can take here, depending on what behavior you want:
"I want to have my collection take ownership of the Monkey objects"
In this case, you'll want to instantiate your OneElementQueue collection to store owned Monkey objects rather than simply [borrowed] Monkey objects, which is the default for class types. You can do this with the one line change (Try it Online):
var q = new owned OneElementQueue(owned Monkey);
In this approach, passing an owned Monkey to your add() method will pass the ownership to the argument and eventually to the collection, making the original object reference invalid (nil).
"I want to have my collection borrow the existing Monkey objects without taking ownership of them"
In this case, you'll need to tell the add() method that the argument passed into it will outlive the argument itself (and then be sure not to lie about it). In Chapel version 1.19, this can be done via lifetime annotations:
proc add(element : eltType) lifetime element > this {
where the annotation lifetime element > this asserts that the actual argument passed through element will outlive the this collection itself, so the compiler should not fear that the borrow will cease to exist once the formal argument has.
Lifetime annotations were not available in Chapel 1.18, so if you're using that version you need to use a slightly bigger hammer and apply pragma "unsafe" to the method. Note that pragmas are not an officially supported feature and may change in the future, so for this case, served as a stopgap until lifetime annotations had been implemented (Try it Online):
pragma "unsafe"
proc add(element : eltType) {

Using Ruby to solve a quiz

So I found this quiz on a website that I was excited to solve with my newly acquired Ruby skills (CodeAcademy, not quite finished yet).
What I want to do is make an array with 100 entries, all set to "open". Then, I planned to create a method containing a for loop that iterates through every nth entry of the array and changes it to either "open" or "closed", based on what it was before. In the for loop, n should be increased from 1 to 100.
What I have so far is this:
change_state = Proc.new { |element| element == "open" ? element = "closed" : element = "open" }
def janitor(array,n)
for i in 1..n
array.each { |element| if array.index(element) % i == 0 then element.change_state end }
end
end
lockers = [*1..100]
lockers = lockers.map{ |element| element = "closed" }
result = janitor(lockers,100)
When trying to execute I receive an error saying:
undefined method `change_state' for "closed":String (NoMethodError)
Anybody an idea what is wrong here? I kinda think I'm calling the "change_state" proc incorrectly on the current array element.
If you know the quiz, no spoilers please!
As you have implemented change_state, it is not a method of any class, and definitely not one attached to any of the individual elements of the array, despite you using the same variable name element. So you cannot call it as element.change_state.
Instead, it is a variable pointing to a Proc object.
To call the code in a Proc object, you would use the call method, and syntax like proc_obj.call( params ) - in your case change_state.call( element )
If you just drop in that change, your error message will change to:
NameError: undefined local variable or method `change_state' for main:Object
That's because the change_state variable is not in scope inside the method, in order to be called. There are lots of ways to make it available. One option would be to pass it in as a parameter, so your definition for janitor becomes
def janitor(array,n,state_proc)
(use the variable name state_proc inside your routine instead of change_state - I am suggesting you change the name to avoid confusing yourself)
You could then call it like this:
result = janitor(lockers,100,change_state)
Although your example does not really need this structure, this is one way in which Ruby code can provide a generic "outer" function - working through the elements of an array, say - and have the user of that code provide a small internal custom part of it. A more common way to achieve the same result as your example is to use a Ruby block and the yield method, but Procs also have their uses, because you can treat them like data as well as code - so you can pass them around, put them into hashes or arrays to decide which one to call etc.
There may be other issues to address in your code, but this is the cause of the error message in the question.

Bang methods in Groovy

Does Groovy have something similar to bang methods on Ruby?
From this blog post:
In Ruby, you can write methods whose names end in ! (exclamation point or “bang”). There’s a lot of confusion surrounding the matter of when, and why, you would want to do so.
The ! in method names that end with ! means, “This method is dangerous”—or, more precisely, this method is the “dangerous” version of an otherwise equivalent method, with the same name minus the !. “Danger” is relative; the ! doesn’t mean anything at all unless the method name it’s in corresponds to a similar but bang-less method name.*
And this site:
You'll find a number of pairs of methods, one with the bang and one without. Those without the bang perform an action and return a freshly minted object, reflecting the results of the action (capitalizing a string, sorting an array, and so on). The bang versions of the same methods perform the action, but they do so in place: Instead of creating a new object, they transform the original object.
This is not a convention in Groovy like it is in Ruby. However you can write methods with names that contain characters like ! with the limitation that it must always be quoted like a string:
// define method with quoted name
def 'dangerous!'() {
// do something dangerous
}
// invoke method with quoted name
'dangerous!'()
No, groovy (currently as of v2.1.4) doesn't have anything like this
To add to your options, another solution that would be more Groovy-like or Java-like would be to include an optional parameter that enabled in-place (a.k.a. dangerous) modification, like so:
def processFoo(Foo item, mutate = false) {
if(!mutate) {
Foo temp = new Foo()
// copy item properties
item = temp
}
item.bar = 'blah blah'
// process item here
return item
}
processFoo(myFoo) // makes a copy
processFoo(myFoo, true) // modifies original
This pattern is used — albeit in the opposite manner — with the sort method on collections. Calling sort(false) on Lists prevents changing the original array. Calling sort() or sort(true) will modify it directly.

How to (if possible) get the reference of an in-memory object (class instance)?

I'm trying to see if there's a way to get a refference of an object which is outside the local (and global) scope, but who exists in memory.
Let's say in my program, i've instantiated an object whose reference is this:
{O:9*\PROGRAM=ZAVG_DELETE_THIS\CLASS=LCL_SMTH}
Far away after tons of calls, in a context where i wouldn't be able to access this object, could i do something like getting the reference of this object simply by knowing the above string?
I was looking into the cl_abap_*descr classes, but i haven't found a method that takes the 'program_name', 'class_name' and 'instance_number', to return the reference of an object.
I'm trying to do this for the purpose of debugging, not to build something that works.
[EDIT 1]:
I assumed that the o:9 string was required in order to get the reference of the object. As pointed out in the response of #mydoghasworms, this isn't the case. It seems that i only need the local name of the variable which holds the reference.
I hope I understand your question correctly, because I am not sure what you mean with "for the purpose of debugging", but here goes:
You can access the variables of another program that are loaded in the memory of the same session (I am pretty sure it does not need to be in the call stack) using:
ASSIGN ('(PROGRAM)VARIABLE') TO LV_LOCAL.
With reference variables, it becomes a bit more tricky, but here is an example that will help to demonstrate.
Here is our calling program that contains a reference variable LR_TEST which we want to access somewhere else. For the purpose of the demonstration, I make reference to a locally defined class (because that's what I gather from your question).
REPORT ZCALLER.
class lcl_test definition.
public section.
data: myval type i.
methods: my_meth exporting e_val type i.
endclass.
data: lr_test type ref to lcl_test.
CREATE OBJECT lr_test.
lr_test->MYVAL = 22.
perform call_me(zcallee).
class lcl_test implementation.
method my_meth.
* Export the attribute myval as param e_val.
e_val = myval.
endmethod.
endclass.
Here is the program in which we want to access a variable from the above program.
REPORT ZCALLEE.
form call_me.
field-symbols: <ref>.
data: ld_test type ref to object.
data: lv_val type i.
* Exhibit A: Gettinf a reference to a 'foreign' object instance
assign ('(ZCALLER)LR_TEST') to <ref>.
* <ref> now contains a reference to the class instance from the program
* ZCALLER (not very useful, except for passing around maybe)
* Exhibit B: Getting a public attribute from a 'foreign' class instance
assign ('(ZCALLER)LR_TEST->MYVAL') to <ref>.
* <ref> now contains the value of the attribute MYVAL
* Exhibit C: Getting a reference to an instance and calling a method
assign ('(ZCALLER)LR_TEST') to <ref>. "Again the class reference
if sy-subrc = 0. "Rule: Always check sy-subrc after assign before
"accessing a field symbol! (but you know that)
ld_test = <ref>. "Now we have a concrete handle
* Now we make a dynamic method call using our instance handle
CALL METHOD ld_test->('MY_METH')
IMPORTING
e_val = lv_val.
endif.
endform.

How do I Extract a Method That Assigns Two Values?

Extract Method (a refactoring from Fowler's book) works great if your method doesn't assign any values. If it assigns one value, that becomes the return value of the extracted method. What if it assigns two values?
Some C# code to illustrate:
private void someBigFunction() {
doSomething();
doSomethingElse();
// start extraction here
string first = Database.Select(...);
// ...
// next is dependent on the value of "first"
int next = Database.Select(...);
// ...
// stop extraction here
doMoreUselessStuff();
}
The exact code or values are not important here. The point is extracting this method. (The two values are linked, so it makes sense to have them in the same method -- and not to make two methods.)
Possible answers to this question would be "return both in an array," "return them both in a pair-like data structure," or "use out parameters (pass by reference)" -- but I'm looking for something cleaner. (The actual code is in Delphi, not C#)
Perhaps Sprout Class is what you're looking for. Make the two members instance variables of a new class and extract this method into that class, assigning the instance variables and providing getters for the caller. Or, of course, you could convert the local variables to be instance variables of the original class. That conversion frequently makes Extract Method easier, but you wind up with what is arguably an excess of instance variables. With Sprout class, you have a class whose only purpose is to retrieve and provide those values, so there's no question that they deserve to be instance variables in it.

Resources