I'm not sure which tag I should use to document singletons like the following:
var singleton = {
c: 1,
f: function(){
return this.c;
}
}
When I use #namespace the member function f will be declared as <static>, and I'ts not a namespace anyway. But it's obviously neither a #class. Is there a separate tag or trick you use for singletons?
Related
I'm trying to use a class defined in a library but I only receive an error as a result.
[LibraryProject]/library/model/Update.gs
class Update {
constructor(obj = {}) {
if(typeof obj == "string"){
options = JSON.parse(obj);
}
Object.assign(this, obj);
}
text(){
return (this.message && this.message.text)?this.message.text:''
}
}
TASKS
✅ Create a new version of the project. (File > Manage versions...)
✅ Load this library in another project [Alias: CustomService] (Resources > Libraries...)
✅ Use functions of CustomService
❌ Use class of CustomService
If I try to use a Class
[NormalProject]/index.gs
function test (){
Logger.log(CustomService.libraryFunction())
var update = new CustomService.Update("");
Logger.log(update)
}
TypeError: CustomService.Update is not a constructor (línea 3, archivo "Code")
How can I instantiate an Object of this Class?
If I run...
Logger
As written in the official documentation,
Only the following properties in the script are available to library users:
enumerable global properties
function declarations,
variables created outside a function with var, and
properties explicitly set on the global object.
This would mean every property in the global this object are available to library users.
Before ES6, All declarations outside a function (and function declaration themselves) were properties of this global object. After ES6, There are two kinds of global records:
Object record- Same as ES5.
Function declarations
Function generators
Variable assignments
Declarative record - New
Everything else - let, const, class
Those in the declarative record are not accessible from the global "object", though they are globals themselves. Thus, the class declaration in the library is not accessible to library users. You could simply add a variable assignment to the class to add a property to the global object(outside any function):
var Update = class Update{/*your code here*/}
References:
Library official documentation
Global environment records
Related Answers:
ES6- What about introspection
Do let statements create properties on the global object
Based on your tests, it appears that you cannot directly import a class from a GAS library. I'd recommend creating a factory method to instantiate the class instead.
Something along these lines:
// Library GAS project
/**
* Foo class
*/
class Foo {
constructor(params) {...}
bar() {...}
}
/* globally accessible factory method */
function createFoo(fooParams) {
return new Foo(fooParams);
}
// Client GAS project
function test() {
var foo = FooService.createFoo(fooParams);
Logger.log(foo.bar());
}
Is there a way I could extend the given pseudo methods for lists in e, to add some specific implementation?
Thanks
"pseudo method" is not really a method, it just looks as if it was. So it cannot be extended with "is also/only/etc".
but you can define any "pseudo method" of your own, using macro.
for example - pseudo method that adds only even items -
(do note the \ before the () )
define <my_pseudo_method'action> "<input1'exp>.add_if_even\(<input2'num>\)"
as computed {
result = append("if ", <input2'num>, " %2 == 0 then { ", <input1'exp>, ".add(", <input2'num>, ")};");
}
then can be called from another file -
extend sys {
run() is also {
var my_list : list of int;
for i from 0 to 10 {
my_list.add_if_even(i);
};
print my_list;
};
};
Using a macro, you can even "override" an existing pseudo-method. For example, let's say you want to modify add() so that it will add an element to the list only if it is not already in the list. (In other words, you want to keep all elements in the list unique).
You can do something like this:
define <my_add'action> "<list'exp>.add\(<exp>\)" as {
if not <list'exp>.has(it == <exp>) then {
var new_size<?>: int = <list'exp>.size() + 1;
<list'exp>.resize(new_size<?>, TRUE, <exp>, TRUE);
};
};
Note that I use another pseudo-method here - resize() - to implement the actual addition of the new element to the list. If I tried to use the add() pseudo-method itself, it wouldn't work, and would lead to an infinite recursion. This is because add() used inside the macro would again call the macro itself, and not the pre-defined pseudo-method being overridden.
You can also use templates to add/modify list pseudo-methods. e.g.
<'
template struct MyList of (<T1'type>) {
items: list of <T1'type>;
keep soft items.size()==10;
pop_index(i:int):<T1'type> is {
result = items[i];
items.delete(i);
};
};
extend sys {
list1: MyList of (byte);
// somehwere
var foo:= list1.pop_index(3);
};
'>
I've detected a very weird behavior in coffeescript.
class Foo
list: []
add: (val)->
#list.push(val)
x = new Foo()
x.add(1)
console.log(x.list.length) // 1
y = new Foo()
y.add(1)
console.log(y.list.length) // 2
So as you see the #list property got shared between the two class instances in a strange way.
I've never faced similar issue before, in coffeescript.
Convert it to JavaScript:
var Foo, x, y;
Foo = (function() {
function Foo() {}
Foo.prototype.list = [];
Foo.prototype.add = function(val) {
return this.list.push(val);
};
return Foo;
})();
As you can see, Foo.prototype.list is a property of the prototype, not of an instance of your class. There's only one array and it will be shared across all of the instances of your class.
To make list an instance variable, add it to the constructor:
class Foo
constructor: ->
#list = []
add: (val)->
#list.push(val)
How do I write a class that implements this TypeScript interface (and keeps the TypeScript compiler happy):
interface MyInterface {
(): string;
text2(content: string);
}
I saw this related answer:
How to make a class implement a call signature in Typescript?
But that only works if the interface only has the bare function signature. It doesn't work if you have additional members (such as function text2) to be implemented.
A class cannot implement everything that is available in a typescript interface. Two prime examples are callable signatures and index operations e.g. : Implement an indexible interface
The reason is that an interface is primarily designed to describe anything that JavaScript objects can do. Therefore it needs to be really robust. A TypeScript class however is designed to represent specifically the prototype inheritance in a more OO conventional / easy to understand / easy to type way.
You can still create an object that follows that interface:
interface MyInterface {
(): string;
text2(content: string);
}
var MyType = ((): MyInterface=>{
var x:any = function():string { // Notice the any
return "Some string"; // Dummy implementation
}
x.text2 = function(content:string){
console.log(content); // Dummy implementation
}
return x;
}
);
There's an easy and type-safe way to do this with ES6's Object.assign:
const foo: MyInterface = Object.assign(
// Callable signature implementation
() => 'hi',
{
// Additional properties
text2(content) { /* ... */ }
}
)
Intersection types, which I don't think were available in TypeScript when this question was originally asked and answered, are the secret sauce to getting the typing right.
Here's an elaboration on the accepted answer.
As far as I know, the only way to implement a call-signature is to use a function/method. To implement the remaining members, just define them on this function. This might seem strange to developers coming from C# or Java, but I think it's normal in JavaScript.
In JavaScript, this would be simple because you can just define the function and then add the members. However, TypeScript's type system doesn't allow this because, in this example, Function doesn't define a text2 member.
So to achieve the result you want, you need to bypass the type system while you define the members on the function, and then you can cast the result to the interface type:
//A closure is used here to encapsulate the temporary untyped variable, "result".
var implementation = (() => {
//"any" type specified to bypass type system for next statement.
//Defines the implementation of the call signature.
var result: any = () => "Hello";
//Defines the implementation of the other member.
result.text2 = (content: string) => { };
//Converts the temporary variable to the interface type.
return <MyInterface>result;
})(); //Invokes the closure to produce the implementation
Note that you don't need to use a closure. You could just declare your temporary variable in the same scope as the resulting interface implementation. Another option is to name the closure function to improve readability.
Here's what I think is a more realistic example:
interface TextRetriever {
(): string;
Replace(text: string);
}
function makeInMemoryTextRetriever(initialText: string) {
var currentText = initialText;
var instance: any = () => currentText;
instance.Replace = (newText: string) => currentText = newText;
return <TextRetriever>instance;
}
var inMemoryTextRetriever = makeInMemoryTextRetriever("Hello");
For example suppose I have
class Parent {
def method() {
var myvar = "test"
}
}
Is there any mechanism for accessing myvar in child classes?
Edit:
I'm trying to build a DSL modeled upon an existing language. That language has features such as
onTrade {
if (price == ...) // will compile
}
onDayStart {
if (price == ...) // will not compile
}
It is as if price is a global variable but there are compile time checks to make sure it is only used in the correct context. I was thinking one way to simulate this would be to have local variables that could be overridden in subclasses. Something like
// Parent
onTrade {
var price = ...
}
// Child
onTrade {
if (price == ...)
if (somethingelse == ...) // will not compile
}
Not really. That's scope for you. If you want it to be visible at different levels, you should probably change the scope of the variable itself.
For example, if you want to define it at the class level, you can share it that way. Local variables wouldn't be local if they weren't actually, well, local.
Scopes are nested, from the most broad, to the most local. Chapter 2, pg. 16 of the Scala Language Reference covers "Identifiers, Names, and Scopes" which explains this in more technical detail.
Possible solution for your problem (though I don't see a way to get rid of new):
// parent
var onTrades = List[OnTrade]()
class OnTrade {
var price = ...
...
onTrades = this :: onTrades
}
// child
new OnTrade {
if (price == ...) {...} // subclass constructor, will call OnTrade constructor first
}