I'm currently in the code generation phase of building a compiler for a Java-like language. I'm trying to understand how to implement dynamic dispatch for virtual methods.
I get how to build a virtual function table for every class and store a pointer to it in every object. What I don't get is- when generating code for a function call, how do you know what the offset is for that function in the table?
Thanks.
How do you know what anything is in your language? You write it down somewhere while parsing.
What I did in one of my toy languages was to keep a "vtable size" for each class, and when you add a new method to a class, you write down the vtable size as the offset of the method somewhere (i.e. you create a lookup table that maps method name to info about it, like its parameter types and its offset in the vtable), then add to the size to account for the newly-added method.
Of course, this assumes your language actually uses a vtable, like for example C++. If you use messaging in the style of Smalltalk or Objective-C, this table that you build actually gets saved to your compiled product and just used directly. Now a table look-up is slower than just accessing an offset directly, but also has the advantage that a caller does not need to know the type of an object to call a method on it, and you can easily add methods to objects without having to recompile the entire program.
Related
I would like to call an API to enrich an existing dataset.
The existing dataset is a CSVDataSet configured in the catalog.
Now I would like to create a Node, that enriches the CSVDataSet with data from the API, that I have to call for every row in the CSV file. Then save the data into a database (SQLTableDataSet). My approach is to create an APIDataSet entry in the catalog and provide it as an input for the node, next to the CSVDataSet.
The issue here is, the APIDataSet is static (in general the DataSets seem to be very static). I need to call the load function at runtime within the Node for every entry in the csv file.
I didn't find a way to do this. Is it just a bad approach? Do I have to call the API within the Node instead of creating a APIDataSet?
So typically, we don't like our nodes having knowledge of IO configuration. The belief is that functionally pure python functions are easier to test, maintain and build.
Typically the way we would keep this distinction would be for you to subclass our APIDataSet / CSVDataSet or both and then add your custom logic to do it all there.
I have done this in my GDALRasterDataSet implementation. The idea is that if you need to enrich a dataset on the go, you can overload the load() method in a custom dataset and pass additional parameters there.
You can see an implementation here and an example of usage here.
The only extra thing you need to do is to re-write the load() method to accept kwargs (line 143) and write your own _load method that enriches your dataset. Everything else is boilerplate.
It seems like there are two styles for writing NEAR smart contracts in assembly script
Bag of functions like Meme Museum
Singleton style like Lottery.
I was wondering under what circumstance one style is recommended over the other.
When should you use one over the other? What are the advantages/disadvantages of each style?
The big differences is in initialization of the contract.
Bag of Functions (BoF)
For the first style, usually a persistent collection is declared at the top level. All top level code in each file is placed into a function and one start function calls each. The Wasm binary format allows to specify the start function so that anytime the binary is instantiated (e.i. loaded by a runtime) that function is called before any exported functions can be called.
For persistent collections this means allocating the objects, but no data is required from storage, until something is read, including the length or size of the collection.
Singleton
A top level instance of the contract is declared. Then storage is checked for the "STATE" key, which contains the state of the instance. If it is present storage is read and the instance is deserialized from storage. Then each "method" of the contract is an exported function that uses the global instance, e.g. instance.method(...), passing the arguments to the method. If the method is decorated with #mutateState then the instance is written back to storage after the method call.
Which To Use
Singleton's provide a nice interface for the contract and is generally easier to understand. However, since you are reading from storage at every method call, it can be more expensive.
The other advantage of the BoF is it's easier to extend as you can export more functions from a dependency.
However, it's also possible to use a combination of both as well.
So really it's whatever makes sense to you.
I was reading about reflect.MakeFunc and was wondering if there's also a way to create a Method (a function with a receiver) at runtime.
No, this is not possible because the receiver's type method set would change on runtime if you did this. As you may know, Go in its current implementations is type checked at compile time. You would require runtime interface-implementation checks on every function-call that takes an interface argument if a type could suddenly acquire (or lose) methods at runtime.
a way to create a Method (a function with a receiver) at runtime
Technically, though, you could build a value representing a method attached to an arbitrary type by forking the reflect package. This would not, however, change said type's method set because it'd be essentially a hack around Go's type system.
What about swapping method pointers on an object?
Go, unlike e.g. Java does not embed a virtual method dispatch table in concrete values, only in interface values. If you're willing to get your hands dirty you could get a hold of a reflect.nonEmptyInterface and modify its itable (itab field).
I'm trying to create a service where a user needs to operate over a data and can manipulate it in numerous ways, so I'm not aware of the manipulations at the time of compiling of my program. One way to achieve this is to give the user a function with data as param. Which landed me in the following direction.
Dynamically create a function
Dynamically linking a function after compiling it separately.
I'm open to suggestions. If you have other ways to achieve the end goal.
If you don't like this as an answer I can move to the comment section, but it's rather long that's why I put here in the answer section.
Dynamically Dispatched Method: The only way to have dynamically dispatched methods is through an interface. Methods on a struct or any other concrete type are always resolved statically.
Closure: Go supports anonymous functions, which can form closures. Anonymous functions are useful when you want to define a function inline without having to name it.
Dyncamically call method on Interface:
Please let me know if that helps you to understand the concept in golang.
Sandy Metz says (POODR book, page 26):
Because it is possible to wrap every instance variable in a method and to therefore treat any variable as if it's just another object, the distinction between data and a regular object begins to disappear.
I am not sure if I understand what she is explaining. When we define the accessors, we are wrapping the instance variables (data) on a method but methods are not objects. So what does she mean when she says that we can treat variables as if they're just another object?
The primary difference between data and objects is behaviour. Objects can modify their internal state without changing their interfaces, while data are static structures.
When we wrap data access within a method, we get the same benefits of an object - the interface remains static to consumers even if the underlying data structure needs to change.