V8's ObjectTemplate provides us two ways to attach a so-called accessor property to the object under instantiation.
The first one is ObjectTemplate::SetAccessor:
/**
* Sets an accessor on the object template.
*
* Whenever the property with the given name is accessed on objects
* created from this ObjectTemplate the getter and setter callbacks
* are called instead of getting and setting the property directly
* on the JavaScript object.
*
* \param name The name of the property for which an accessor is added.
* \param getter The callback to invoke when getting the property.
* \param setter The callback to invoke when setting the property.
* \param data A piece of data that will be passed to the getter and setter
* callbacks whenever they are invoked.
* \param settings Access control settings for the accessor. This is a bit
* field consisting of one of more of
* DEFAULT = 0, ALL_CAN_READ = 1, or ALL_CAN_WRITE = 2.
* The default is to not allow cross-context access.
* ALL_CAN_READ means that all cross-context reads are allowed.
* ALL_CAN_WRITE means that all cross-context writes are allowed.
* The combination ALL_CAN_READ | ALL_CAN_WRITE can be used to allow all
* cross-context access.
* \param attribute The attributes of the property for which an accessor
* is added.
* \param signature The signature describes valid receivers for the accessor
* and is used to perform implicit instance checks against them. If the
* receiver is incompatible (i.e. is not an instance of the constructor as
* defined by FunctionTemplate::HasInstance()), an implicit TypeError is
* thrown and no callback is invoked.
*/
void SetAccessor(
Local<String> name, AccessorGetterCallback getter,
AccessorSetterCallback setter = nullptr,
Local<Value> data = Local<Value>(), AccessControl settings = DEFAULT, // note the data is on the template level.
PropertyAttribute attribute = None, // not on the instance level.
Local<AccessorSignature> signature = Local<AccessorSignature>(),
SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect,
SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect);
and the second one is Template::SetAccessorProperty:
void SetAccessorProperty(
Local<Name> name, // The latter one is called data property.
Local<FunctionTemplate> getter = Local<FunctionTemplate>(),
Local<FunctionTemplate> setter = Local<FunctionTemplate>(),
PropertyAttribute attribute = None,
AccessControl settings = DEFAULT);
Having two very similar APIs confuses me a lot.
Unfortunately there is no docs describing their differences, so I have to do experiment on my own. I found that the combination of Holder() and SetAccessor() will break, while other combinations of Holder() or This() and SetAccessor() or SetAccessorProperty() work fine. On a previous post I ran into this failing combination and was fooled to believe what's went wrong is Holder() or This(). But after the experiment I now believe that it is SetAccessor went wrong.
My question is, whether SetAccessor is a deprecated API? If so, all we have to do is stop using it. If not so, please explain a little bit their differences, esspecially in causing this failure. Many thanks to the warm-hearted and experienced V8 developers!
I agree that the names can be a bit confusing; neither is deprecated. The difference is as follows:
SetAccessor creates a "magic" data property: it looks like a data property to JavaScript (getOwnPropertyDescriptor returns {value: ..., ...}), but when reading/writing the property, the C++ callbacks you specified will be called. For a built-in example, think of Array.prototype.length (where in particular the setter has to do additional work when you use a .length assignment to shorten an array).
SetAccessorProperty creates a regular accessor property, i.e. getOwnPropertyDescriptor returns {get: ..., set: ..., ...}. A built-in example would be Int32Array.prototype.__proto__.byteLength. The name "SetAccessorProperty" reflects the fact that the JS spec calls these properties "accessor properties".
Chances are that in many cases, this difference doesn't matter: interfacing JavaScript code can read and/or write properties either way. But sometimes you might have a reason to care about the distinction, and in that case V8's API gives you that flexibility.
Related
The constructor for the SimpleRetryPolicy allows you to specify which exceptions are retryable. Great!
However, this input is a map where the key is the class of the Throwable, and the value is a boolean. There isn't any documentation on what this boolean value is used for- does anyone here know?
Essentially, it populates an instance of a SubclassClassifier whose documentation is too difficult for my simple mind to understand:
A Classifier for a parameterised object type based on a map. Classifies objects according to their inheritance relation with the supplied type map. If the object to be classified is one of the keys of the provided map, or is a subclass of one of the keys, then the map entry value for that key is returned. Otherwise returns the default value which is null by default.
See SimpleRetryPolicy.retryForException():
/**
* Delegates to an exception classifier.
*
* #param ex
* #return true if this exception or its ancestors have been registered as
* retryable.
*/
private boolean retryForException(Throwable ex) {
return retryableClassifier.classify(ex);
}
i.e. if the throwable is classified (is in the map), the boolean value of that map entry is returned.
This allows you to set up a set of exceptions where you explicitly state that you don't want to retry some exception.
Consider exception Bar extends Foo (and Bar has some sibling classes, say Baz, Qux).
If you add Foo:true to the map and Bar:false then Foo and all its subclasses except Bar are retryable.
The reference documentation for the class NSUniqueIdentifier claims that unique ID specifiers are evaluated in the following scheme:
If the container implements a method whose selector matches the relevant valueIn<Key>WithUniqueID: pattern established by scripting
key-value coding, the method is invoked. This method can potentially
be very fast, and it may be relatively easy to implement.
As is the case when evaluating any script object specifier, the container of the specified object is given a chance to evaluate the
object specifier. If the container class implements the
indicesOfObjectsByEvaluatingObjectSpecifier: method, the method is
invoked. This method can potentially be very fast, but it is
relatively difficult to implement.
An NSWhoseSpecifier object that specifies the first object whose relevant 'ID ' attribute matches the ID is synthesized and evaluated.
The NSWhoseSpecifier object must search through all of the keyed
elements in the container, looking for a match. The search is
potentially very slow.
However, I am not seeing valueIn<Key>WithUniqueID: getting called. To give you an example, I have a class where I describe the object specifier in the following way:
- (NSScriptObjectSpecifier *)objectSpecifier
{
assert(self.documentID);
assert(self.controller);
NSScriptObjectSpecifier *containerRef = self.controller.objectSpecifier;
assert(containerRef);
assert(containerRef.keyClassDescription);
return [[NSUniqueIDSpecifier alloc] initWithContainerClassDescription:containerRef.keyClassDescription
containerSpecifier:containerRef
key:#"allObjects"
uniqueID:self.documentID];
}
The method I have defined in the container class is - (id)valueInAllObjectsWithUniqueID:(NSString *)uniqueID is the method I have defined:
- (id)valueInAllObjectsWithUniqueID:(NSString *)uniqueID {
return [self objectWithIdentifier:uniqueID];
}
In the class corresponding to the container I've also overridden -respondsToSelector: to debug this further, and observe that the only relevant method the scripting system queries is indicesOfObjectsByEvaluatingObjectSpecifier: right after -objectSpecifier above is called (and confirmed to return a non-nil result with the container class description and container specifier consistent with the container's class receiving method calls right after the object specifier is evaluated).
Any ideas? This is on OSX Mavericks (10.9.4).
Is the syntax for TypeScript comments documented anywhere?
And by any chance, does it now support the C# /// system?
Current
The TypeScript team, and other TypeScript involved teams, created a TSDoc specification. https://tsdoc.org/
Example straight from the docs:
export class Statistics {
/**
* Returns the average of two numbers.
*
* #remarks
* This method is part of the {#link core-library#Statistics | Statistics subsystem}.
*
* #param x - The first input number
* #param y - The second input number
* #returns The arithmetic mean of `x` and `y`
*
* #beta
*/
public static getAverage(x: number, y: number): number {
return (x + y) / 2.0;
}
}
Past
TypeScript uses JSDoc. e.g.
/** This is a description of the foo function. */
function foo() {
}
To learn jsdoc : https://jsdoc.app/
But you don't need to use the type annotation extensions in JSDoc.
You can (and should) still use other jsdoc block tags like #returns etc.
Just an example. Focus on the types (not the content).
JSDoc version (notice types in docs):
/**
* Returns the sum of a and b
* #param {number} a
* #param {number} b
* #returns {number}
*/
function sum(a, b) {
return a + b;
}
TypeScript version (notice the re-location of types):
/**
* Takes two numbers and returns their sum
* #param a first input to sum
* #param b second input to sum
* #returns sum of a and b
*/
function sum(a: number, b: number): number {
return a + b;
}
Update November 2020
A website is now online with all the TSDoc syntax available (and that's awesome): https://tsdoc.org/
For reference, old answer:
The right syntax is now the one used by TSDoc. It will allow you to have your comments understood by Visual Studio Code or other documentation tools.
A good overview of the syntax is available here and especially here. The precise spec should be "soon" written up.
Another file worth checking out is this one where you will see useful standard tags.
Note: you should not use JSDoc, as explained on TSDoc main page: Why can't JSDoc be the standard? Unfortunately, the JSDoc grammar is not rigorously specified but rather inferred from the behavior of a particular implementation. The majority of the standard JSDoc tags are preoccupied with providing type annotations for plain JavaScript, which is an irrelevant concern for a strongly-typed language such as TypeScript. TSDoc addresses these limitations while also tackling a more sophisticated set of goals.
You can add information about parameters, returns, etc. as well using:
/**
* This is the foo function
* #param bar This is the bar parameter
* #returns returns a string version of bar
*/
function foo(bar: number): string {
return bar.toString()
}
This will cause editors like VS Code to display it as the following:
You can use comments like in regular JavaScript:
1 Introduction
[...] TypeScript syntax is a superset of ECMAScript 2015 (ES2015) syntax.
2 Basic Concepts
[...] This document describes the syntactic grammar added by TypeScript [...]
Source: TypeScript Language Specification
The only two mentions of the word "comments" in the spec are:
1 Introduction
[...] TypeScript also provides to JavaScript programmers a system of optional type annotations. These type annotations are like the JSDoc comments found in the Closure system, but in TypeScript they are integrated directly into the language syntax. This integration makes the code more readable and reduces the maintenance cost of synchronizing type annotations with their corresponding variables.
11.1.1 Source Files Dependencies
[...] A comment of the form /// <reference path="..."/> adds a dependency on the source file
specified in the path argument. The path is resolved relative to the directory of the containing source file.
TypeScript is a strict syntactical superset of JavaScript hence
Single line comments start with //
Multi-line comments start with /* and end with */
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.
I am an experienced programmer learning Ruby (and liking it a lot).
I'm working on setting up a database using SQLite3.
In order to better learn Ruby, I'm tracing into SQLite3.
What I don't understand is, where is the code for #new for the Database and Statement classes.
Actually, I expect not a #new method, but a #initialize method.
SQLite3::Database.new(file, options = {})
SQLite3::Statement.new(db, sql)
The above two statements are from the documentation.
But in my code when I try to trace into this
$db = SQLite3::Database.new"MyDBfile"
it just steps over.
Then later on when I try to trace into
#$db.execute
I do get into the #execute method in the Database.rb file, but then it calls the #prepare method where I try to step into
stmt = SQLite3::Statement.new( self, sql )
but again no luck. It just steps over it.
I've scoured the source code, done searches etc but I cannot locate the initialize methods that are being called. Where are they ?
Thank you for considering this question.
The initialize method for SQLite3::Database is implemented in C:
/* call-seq: SQLite3::Database.new(file, options = {})
*
* Create a new Database object that opens the given file. If utf16
* is +true+, the filename is interpreted as a UTF-16 encoded string.
*
* By default, the new database will return result rows as arrays
* (#results_as_hash) and has type translation disabled (#type_translation=).
*/
static VALUE initialize(int argc, VALUE *argv, VALUE self)
Similarly for SQLite3::Statement:
/* call-seq: SQLite3::Statement.new(db, sql)
*
* Create a new statement attached to the given Database instance, and which
* encapsulates the given SQL text. If the text contains more than one
* statement (i.e., separated by semicolons), then the #remainder property
* will be set to the trailing text.
*/
static VALUE initialize(VALUE self, VALUE db, VALUE sql)
The Ruby debugger doesn't know how to step into C functions (assuming the SQLite3 extensions have even been compiled with debugging support) so it skips over them.