Why does instance method doesn't work? - coffeescript

I'm studying coffescript. I want an instance method (#generate_human) to run during every instantination of the class, but I'm getting error that the function doesn't exist. When I change the method to be the class method instead, everything works. What is going on?
class Human # As biological creature
constructor: (#given_sex = null,
#age = null, # Age of the person
#max_age = 85) -> # Maximum allowed age of the person during person generation
_alive = true
alive: ->
#_alive
dead: ->
not #alive()
has_died: ->
#_alive = false
_available_sexes: {0: 'female', 1: 'male'}
sex: ->
_sex = #_available_sexes[#given_sex]
generate_human: ->
#_alive = true
if #age is null
#age = Math.floor(Math.random() * #max_age)
if #given_sex is null
#given_sex = Math.floor(Math.random() * 2)
else if #given_sex not in [0,1]
n = #given_sex
err = 'Invalid sex value: ' + n
console.log(err)
throw new Error(err)
#generate_human() # In JavaScript this line throws an error that function 'this.generate_human()' does not exist
h = new Human()

At the class level, # (AKA this) is the class itself. When you say this:
class C
#m()
the # in #m() will be referring to the class itself, not an instance of the class. If you look at the JavaScript version you should see what's going on:
var C = (function() {
function C() {}
C.m(); // <---------- This is the #m() call.
return C;
})();
This lines up with the syntax for defining a class method:
class C
#m: ->
which becomes this JavaScript:
var C = (function() {
function C() {}
C.m = function() {}; // <--------- Here is the class method.
return C;
})();
If you want the method to run when an instance is created, call it in constructor:
class Human
constructor: (#given_sex = null, #age = null, #max_age = 85) ->
#generate_human()
#...
You probably want to look at what CoffeeScript does to that _alive = true too, that doesn't define a default #_alive instance variable, that is actually a private class variable of sorts; you probably want _alive: true instead.
Also, you should be very very careful and consistent with your whitespace in CoffeeScript, any variation or inconsistency can cause strange and puzzling errors. For example, I'd recommend against that format for your constructor definition and you'll have a better time if all your methods are at the same indentation level.

Related

I need to gen several bools simultaneously

I have:
struct MyStruct {
!Ipv4En : bool;
!Ipv6En : bool;
keep Ipv4En == TRUE or Ipv6En == TRUE;
MyMethod() is {
gen Ipv4En;
gen Ipv6En;
};
};
I always get Ipv4En TRUE, because those 2 bools are not generated together.
They can't be generated when I gen MyStruct.
How can I generate them together?
Meanwhile I patched it (don't like the solution):
I've deleted ! in the definition.
temp : MyStruct;
gen temp;
Ipv4En = temp.Ipv4En;
Ipv6En = temp.Ipv6En;
Since a gen action only takes a single gen-item, you have to group the two variables you want solved together. You can do this by defining a new struct:
struct IpVersionInfo {
Ipv4En: bool;
Ipv6En: bool;
keep Ipv4En == TRUE or Ipv6En == TRUE;
};
Instead of having two variables for your enables, you use a single variable of this new struct type:
struct MyStruct {
!ipVersionInfo: IpVersionInfo;
MyMethod() is {
gen ipVersionInfo;
};
};
If you run a couple of iterations, you'll see that you can reach all combinations:
extend sys {
run() is also {
for i from 1 to 20 {
var s: MyStruct = new;
s.MyMethod();
outf(
"Ipv4En = %s, Ipv6En = %s\n",
s.ipVersionInfo.Ipv4En,
s.ipVersionInfo.Ipv6En);
};
};
};
This requires an API change, though, so you'll need to update all code that referenced Ipv4En and Ipv6En.
Aside from grouping the two fields in a struct, there are also other ways of solving your problem. Another example would be to define an enum that contains values for your legal cases:
type ip_version_info_e: [ V4, V6, BOTH ];
As before, you can use a variable of this type in your struct:
struct MyStruct {
!ip_version_info: ip_version_info_e;
MyMethod() is {
gen ip_version_info;
};
};
If you run a couple of iterations of the new code you'll see that it also reaches all possible combinations:
extend sys {
run() is also {
for i from 1 to 20 {
var s: MyStruct = new;
s.MyMethod();
outf(
"Ipv4En = %s, Ipv6En = %s\n",
s.ip_version_info in [ V4, BOTH ],
s.ip_version_info in [ V6, BOTH ]);
};
};
};
Regardless of how you decide to solve the problem, you should hide the internal implementation from any client code that uses MyStruct. Notice that the out statements from above look different depending on how we chose to handle the IP version settings. Instead of having client code look too deep inside MyStruct you should define the following two methods:
isIpv4Enabled(): bool;
isIpv6Enabled(): bool;
In the case where we grouped the two Boolean variables in a struct, the implementations of these two methods are:
struct MyStruct {
// ...
isIpv4Enabled(): bool is {
result = ipVersionInfo.Ipv4En;
};
isIpv6Enabled(): bool is {
result = ipVersionInfo.Ipv6En;
};
};
In the case where we defined an enum, we have:
struct MyStruct {
// ...
isIpv4Enabled(): bool is {
result = ip_version_info in [ V4, BOTH ];
};
isIpv6Enabled(): bool is {
result = ip_version_info in [ V6, BOTH ];
};
};
In both cases, though, the client code for printing would be the same:
extend sys {
run() is also {
for i from 1 to 20 {
var s: MyStruct = new;
s.MyMethod();
outf(
"Ipv4En = %s, Ipv6En = %s\n",
s.isIpv4Enabled(),
s.isIpv4Enabled());
};
};
};
This is a major advantage. This way you are free to change your implementation of MyStruct in the future and not have to touch any other code that uses it.

Swift: accessing computed property through pointer

I was playing around with trying to get/set a computed property of an object through a pointer to that property. I've included the code snippet and output below.
The gist of the snippet is that there's a class Foo with a computed property bar. The Mutator class keeps a pointer and has a computed property value that just gets/sets the value it points to. So, if I create f1: Foo and then a m1: Mutator object that references that f1.bar, I would think that setting m1.value would also set f1.bar1. It works sometimes, but not always.
//---------------------------------------------------------------------------
// Class definitions
class Foo
{
private var data = [String: Double]()
var bar: Double?
{
get { return self.data["bar"] }
set { self.data["bar"] = newValue }
}
init(_ key: String, _ val: Double)
{
self.data[key] = val
}
}
class Mutator
{
let name: String
let storage: UnsafeMutablePointer<Double?>
var value: Double?
{
get { return self.storage.pointee }
set { self.storage.pointee = newValue}
}
init(name: String, storage: UnsafeMutablePointer<Double?>)
{
self.name = name
self.storage = storage
}
}
//---------------------------------------------------------------------------
// Create and display mutators directly
print("-\nCreate and display mutator directly")
let f1 = Foo("bar", 1.1)
let f2 = Foo("bar", 2.2)
let f3 = Foo("bar", 3.3)
let m1 = Mutator(name:"mf1", storage: &f1.bar) // Or, let m1 = Mutator(name:"f1", storage: UnsafeMutablePointer<Double?>(&f1.bar))
let m2 = Mutator(name:"mf2", storage: &f2.bar)
let m3 = Mutator(name:"mf3", storage: &f3.bar)
var before = m1.value
m1.value = 199.1
var after = m1.value
print("\(m1.name): before=\(before), after=\(after) # \(m1.storage)")
before = m2.value
m2.value = 299.2
after = m2.value
print("\(m2.name): before=\(before), after=\(after) # \(m2.storage)")
before = m3.value
m3.value = 299.2
after = m3.value
print("\(m3.name): before=\(before), after=\(after) # \(m3.storage)")
//---------------------------------------------------------------------------
// Create mutators inside function
func createMutators() -> [Mutator]
{
print("-\nIn createMutators function ...")
let m1 = Mutator(name:"mf1", storage: &f1.bar)
let m2 = Mutator(name:"mf2", storage: &f2.bar)
let m3 = Mutator(name:"mf3", storage: &f3.bar)
print("\(m1.name)=\(m1.value) # \(m1.storage)")
print("\(m2.name)=\(m2.value) # \(m2.storage)")
print("\(m3.name)=\(m3.value) # \(m3.storage)")
return [m1, m2, m3]
}
let mutator = createMutators()
//---------------------------------------------------------------------------
// Display mutators returned by function
print("-\nDisplay mutator returned by function")
for m in mutator
{
let before = m.value
m.value = 10.0 + (before ?? Double.nan)
let after = m.value
print("\(m.name): before=\(before), after=\(after) # \(m.storage)")
}
If I run the above code on Linux, I get the following output:
Create and display mutator directly
mf1: before=Optional(1.1000000000000001), after=Optional(199.09999999999999) # 0x00007ffd38f82730
mf2: before=Optional(2.2000000000000002), after=Optional(299.19999999999999) # 0x00007ffd38f82708
mf3: before=Optional(3.2999999999999998), after=Optional(299.19999999999999) # 0x00007ffd38f826e0
-
In createMutators function ...
mf1=Optional(1.1000000000000001) # 0x00007ffd38f82288
mf2=Optional(2.2000000000000002) # 0x00007ffd38f82260
mf3=Optional(3.2999999999999998) # 0x00007ffd38f82238
-
Display mutator returned by function
mf1: before=Optional(4.9406564584124654e-324), after=Optional(10.0) # 0x00007ffd38f82288
mf2: before=Optional(6.9527664311957093e-310), after=Optional(10.0) # 0x00007ffd38f82260
mf3: before=nil, after=Optional(nan) # 0x00007ffd38f82238
The first output block shows expected behavior. The second block points to a different address, which is unexpected. Weirder still is that despite having the wrong address, it reads the correct values. The last output block has the same address as in the second block, but reads different initial values, though it does manage to set and read back the values correctly.
I know this is perhaps an abuse of the computed properties and pointers. But can anyone explain why it works sometimes? Why does creating it in the function give it a different address? Why would reading it in the function and after it's returned give different answers when the addresses are the same? Is there a way to make this work?
Just to confuse things further: the above was from running on Linux. When I try this experiment on a mac I get somewhat different results, though the overall observation that sometimes it works remains true.
None of this is defined behaviour. It may or may not produce expected results, or it may just crash at runtime.
When you say
let m1 = Mutator(name:"mf1", storage: &f1.bar)
Swift will allocate some memory and initialise it to the value returned by f1.bar's getter. A pointer to this memory will then be passed into Mutator's init – and after the call, Swift will then call f1.bar's setter with the (possibly changed) contents of the memory it allocated.
This memory will then be deallocated – the pointer is now no longer valid. Reading and writing to its pointee will produce undefined behaviour. Therefore, you should not persist the pointer after the call to Mutator's initialiser.
One way in order to get the behaviour you want is to use two closures for the getting and setting of f1.bar, both capturing f1. This ensures that the reference to f1 remains valid as long as the closures live.
For example:
struct Mutator<T> {
let getter: () -> T
let setter: (T) -> Void
var value: T {
get {
return getter()
}
nonmutating set {
setter(newValue)
}
}
init(getter: #escaping () -> T, setter: #escaping (T) -> Void) {
self.getter = getter
self.setter = setter
}
}
You can then use it like so:
class Foo {
private var data = [String : Double]()
var bar: Double? {
get { return self.data["bar"] }
set { self.data["bar"] = newValue }
}
init(_ key: String, _ val: Double) {
self.data[key] = val
}
}
let f1 = Foo("bar", 1.1)
let m1 = Mutator(getter: { f1.bar }, setter: { f1.bar = $0 })
let before = m1.value
m1.value = 199.1
print("m1: before = \(before as Optional), after = \(m1.value as Optional)")
print("f1 after = \(f1.bar as Optional)")
// m1: before = Optional(1.1000000000000001), after = Optional(199.09999999999999)
// f1 after = Optional(199.09999999999999)
Although one downside to this approach is the repetition of value you're getting and setting (f1.bar in this case). One alternative implementation would be to use a single closure with a function argument that takes an inout parameter, returning the (possibly mutated) value.
struct Mutator<T> {
let getter: () -> T
let setter: (T) -> Void
var value: T {
get {
return getter()
}
nonmutating set {
setter(newValue)
}
}
init(mutator: #escaping ((inout T) -> T) -> T) {
// a function, which when applied, will call mutator with a function input
// that just returns the inout argument passed by the caller.
getter = {
mutator { $0 }
}
// a function, which when applied with a given new value, will call mutator
// with a function that will set the inout argument passed by the caller
// to the new value, which will then be returned
// (but ignored by the outer function)
setter = { newValue in
_ = mutator { $0 = newValue; return $0 }
}
}
}
// ...
let f1 = Foo("bar", 1.1)
let m1 = Mutator { $0(&f1.bar) }
The getter now simply applies the passed function, returning the inout parameter passed (f1.bar in this case), and the setter uses this inout parameter in order to assign a new value.
Although personally, I prefer the first approach, despite the repetition.
The Swift language definition does not require it to not move (or reuse) the memory used by class object instance properties, once outside the block or scope where unsafe pointers and other internal references are valid.
So, in your second and third case, the object (or some of its properties) has likely been moved and you are examining and (dangerously) changing memory where the object used to be, and where part of some completely different type of object might currently be, through a stale (and thus very unsafe) pointer.
So the Swift compiler (which knows when and where it moved stuff) knows how to read and write the property inside the instance. But you (via stale pointers) do not.
Added: If you want to do this type of stuff, then allocate (and manage) the memory yourself (which is possible in Swift).

Declare dynamically added class properties in TypeScript

I want to assign properties to the instance of a class without knowing the property names, values and types of values in TypeScript. Lets assume we have the following example.ts script:
// This could be a server response and could look totally diffent another time...
const someJson:string = '{ "foo": "bar", "bar": "baz" }'
class MyClass {
someProperty:boolean
constructor( json:string ) {
const parsedJson:any = JSON.parse( json )
Object.keys( parsedJson ).forEach(
( key:string ) => {
this[ key ] = parsedJson[ key ]
}
)
this['someProperty'] = true
}
}
const myInstance = new MyClass( someJson )
// Works fine, logs `true`.
console.log( myInstance.someProperty )
// Error: Property 'foo' does not exist on type 'MyClass'.
console.log( myInstance.foo )
// Error: Property 'bar' does not exist on type 'MyClass'.
console.log( myInstance.bar )
How can I make sure that the TypeScript compiler does not complain of the dynamically added properties but instead handle them as "key": value pairs of any type. I still want tsc to make sure that myInstance.someProperty has to be of type boolean but I want to be able to get myInstance.whatever even if it is not defined without running into compiler errors.
I did not find any documentation that makes this clear to me. Maybe because I'm not a native english speaker. So please keep the answers simple.
Edit:
I remember that there was something like the following but I never got that to work:
interface IMyClass {
[name:string]: any
}
The problem is that you're adding the new properties at runtime and the compiler has no way of knowing that.
If you know the property names in advance then you can do this:
type Json = {
foo: string;
bar: string;
}
...
const myInstance = new MyClass(someJson) as MyClass & Json;
console.log(myInstance.foo) // no error
Edit
If you do not know the properties in advance then you can't do this:
console.log(myInstance.foo);
Because then you know that foo is part of the received json, you'll probably have something like:
let key = getKeySomehow();
console.log(myInstance[key]);
And this should work without an error from the compiler, the only problem with that is that the compiler doesn't know the type for the returned value, and it will be any.
So you can do this:
const myInstance = new MyClass(someJson) as MyClass & { [key: string]: string };
let foo = myInstance["foo"]; // type of foo is string
let someProperty = myInstance["someProperty"]; // type of someProperty is boolean
2nd edit
As you do know the props, but not in the class, you can do:
type ExtendedProperties<T> = { [P in keyof T]: T[P] };
function MyClassFactory<T>(json: string): MyClass & ExtendedProperties<T> {
return new MyClass(json) as MyClass & ExtendedProperties<T>;
}
Then you simply use it like so:
type Json = {
foo: string;
bar: string;
};
const myInstance = MyClassFactory<Json>(someJson);
Note that this will work only on typescript 2.1 and above.
If you want to dynamically add class properties via an object upon instantiation, and type information is available for that object, you can very nicely get full type safety in this way (as long as you don't mind using a static factory method):
class Augmentable {
constructor(augment: any = {}) {
Object.assign(this, augment)
}
static create<T extends typeof Augmentable, U>(this: T, augment?: U) {
return new this(augment) as InstanceType<T> & U
}
}
This is using the (fake) this parameter to infer the constructor type of the class. It then constructs the instance, and casts it to a union of the instance type (using the InstanceType utility type) and the inferred type of the props you passed to the method.
(We could have casted directly to Augmentable & U, however this way allows us to extend the class.)
Examples
Augment basic properties:
const hasIdProp = Augmentable.create({ id: 123 })
hasIdProp.id // number
Augment with methods:
const withAddedMethod = Augmentable.create({
sayHello() {
return 'Hello World!'
}
})
withAddedMethod.sayHello() // Properly typed, with signature and return value
Extend and augment, with this access in method augments:
class Bob extends Augmentable {
name = 'Bob'
override = 'Set from class definition'
checkOverrideFromDefinition() {
return this.override
}
}
interface BobAugment {
whatToSay: string
override: string
sayHelloTo(to: string): void
checkOverrideFromAugment(): string
}
const bobAugment: BobAugment = {
whatToSay: 'hello',
override: 'Set from augment'
sayHelloTo(this: Bob & BobAugment, to: string) {
// Let's combine a class parameter, augment parameter, and a function parameter!
return `${this.name} says '${this.whatToSay}' to ${to}!`
},
checkOverrideFromAugment(this: Bob & BobAugment) {
return this.override
}
}
const bob = Bob.create(bobAugment) // Typed as Bob & BobAugment
bob.sayHelloTo('Alice') // "Bob says 'hello' to Alice!"
// Since extended class constructors always run after parent constructors,
// you cannot override a class-set parameter with an augment, no matter
// from where you are checking it.
bob.checkOverrideFromAugment() // "Set from class definition"
bob.checkOverrideFromDefinition() // "Set from class definition"
Limitations
Augmented properties aren't really part of the class, so you can't extend a class with those augments included. This may be a feature for some use cases where the augments are temporary additions that aren't meant to modify the prototype hierarchy
It is also not easy to add non-augment arguments to .create(), however an easy work-around is to simply utilize the augment functionality to accomplish the same thing you would have with an extra argument.
You can add index signature to your class:
class MyClass {
[index: string]: any; //index signature
someProperty:boolean
constructor( json:string ) {
const parsedJson:any = JSON.parse( json )
Object.keys( parsedJson ).forEach(
( key:string ) => {
this[ key ] = parsedJson[ key ]
}
)
this['someProperty'] = true
}
}

CoffeeScript: lazy evaluation without using parenthesis

I am trying to create a sort of global, singleton object in my CoffeeScript code:
window.MyLib =
Foos: {}
Bars: {}
Client: ->
#_client ||= (
someVar = 'foo'
new ExpensiveClient(someVar)
)
# ...
MyLib.Client.performSomeAction()
However, the code actually requires me to do this:
MyLib.Client().performSomeAction()
How can I get around this problem of implementing a lazy instantiation without needing to use parenthesis to call it as a function?
Update: Alternatively, if there was a way to implement a sort of "method missing", the Client function could return an object that delegates the responsibilities to the actual client, but only instantiate it when it needs to.
Perhaps something like this:
lazyGet = (obj, name, property) ->
Object.defineProperty obj, name, get: property
window.MyLib = do ->
#_client = null
Foos: {}
Bars: {}
lazyGet this, 'Client', ->
#_client ||= (
someVar = 'foo'
new ExpensiveClient someVar
)

Coffeescript function declaration func: -> or func = ->?

I'm reading through the spine.js documentation and I'm wondering a little bit about the function declarations.
In the doc i always read
constructor: ->
super
....
But otherwise i always read
constructor = ->
super
....
So are : and = equal for function declarations?
No.
When defining a class, the : works slightly differently than it does elsewhere. In a class definition the : means to put this function as a method on the prototype (instance method). constructor: is a special case to be used for the constructor function.
The difference is obvious if you look at the compiled javascript.
class Foo
constructor: -> #foo = 'foo'
method: ->
compiles to this (Good!)
var Foo;
Foo = (function() {
function Foo() {
this.foo = 'foo';
}
Foo.prototype.method = function() {};
return Foo;
})();
You can see the constructor is the constructor, and the method is on the prototype.
However, when you use = you simply assign local variables and the functions are not really part of the class as the constructor or the prototype:
class Bar
constructor = -> #bar = 'bar'
method = ->
Compiles to this (Bad!)
var Bar;
Bar = (function() {
var constructor, method;
function Bar() {}
constructor = function() {
return this.bar = 'bar';
};
method = function() {};
return Bar;
})();
Many issues about coffee script syntax can be discovered or resolved by simply looking at the compiled result. And this also why I do not recommend learning coffee script without also knowing JavaScript, as some of the things that it does for don't really make sense if you dont know what it compiles into.