I would like to something like this in JavaScript
var init = function () {
// do some stuff once
var once = true
// overwrite the function
init = function () {
console.log(once)
}
}
CoffeeScript adds another local var init to the initial init so the second init doesn't overwrite the first one
var init = function () {
var init //automatically declared by coffeescript
// do some stuff once
var once = true
// overwrite the function
init = function () {
console.log(once)
}
}
Some tips for solutions / workarounds would be greatly appreciated.
(Update: The answer below was accurate at the time, under CoffeeScript 1.0.1. It is no longer the case under CoffeeScript 1.1.0, which fixed this issue.)
Wow, this surprises me. The CoffeeScript
init = ->
init = -> console.log once
declares both an outer init and an inner init. This strikes me as more likely a bug than a conscious language design decision—the compiler simpler evaluates the function before it evaluates the outer init = assignment. I've gone ahead and filed an issue on this.
Here's a workaround:
init = null
init = ->
init = -> console.log once
Now there's only one init, the one with the outermost scope.
I believe this is by design. You shouldn't rely on implicit globals. init is a property of the window/global object, so just reference it correctly:
window.init = ->
var once = true
window.init = ->
console.log once
Related
I have recently encountered such code block when I was working on a different codebase.
I was wondering is there any significant difference (in terms of memory impact etc.) between these two declarations other than syntactic ease? I regularly use lazy stored properties but I couldn't visualize how a function can be "lazy". Can you guys also enlighten me how functions are processed (or share an article explaining this topic) by the swift compiler as well?
Thanks in advance, wish you bug free codes.
A few differences I can think of off the top of my head:
With functions, you can use parameter labels to make the call site more readable, but since you can't add parameter labels to function types, you can't do that with the lazy var declaration.
// doesn't work
lazy var say: (message: String, to person: String) -> Void = {
...
}
// works
func say(message: String, to person: String) {
...
}
You can only invoke a function type with no parameter labels at all :( say("Hello", "Sweeper") instead of say(message: "Hello", to: "Sweeper").
lazy vars are variables, so someone could just change them:
helloFunc = { /* something else */ }
you could prevent this by adding a private setter, but that still allows setting it from within the same class. With a function, its implementation can never be changed at runtime.
lazy vars cannot be generic. Functions can.
// doesn't work
lazy var someGenericThing<T>: (T) -> Void = {
...
}
// works
func someGenericThing<T>(x: T) {
...
}
You might be able to work around this by making the enclosing type generic, but that changes the semantics of the entire type. With functions, you don't need to do that at all.
If you're implementing a language, the magic you need to implement 'lazy' as a feature is to make the value provided silently be wrapped in a function (of no arguments) that is automatically evaluated the first time the property is read.
So for example if you have
var x = SomeObject() // eagerly construct an instance of SomeObject
and
lazy var x = SomeObject() // construct an instance if/when someone reads x
behind the scenes you have, for the lazy var x, either x has not yet been read, or it has been and therefore has a value. So this is like
enum Lazy<T> {
case notReadYet(() -> T) // either you have a function that makes the initial T
case read(T) // or you have a value for T
}
var thing: Lazy<SomeObject> = .notReadYet { return SomeObject() }
and with a suitable property wrapper or other language magic, wrap the calls to the getter for thing with a switch on the case, which checks if you are in the notReadYet case, and if so automatically invoke the function to produce the T and then set the property to .read(t) for the particular value of t.
If you substitute in your type: () -> Void from your example you have something like:
var thing: Lazy<() -> Void> = .notReadYet({ return { print("Hello") } })
This is all rather odd because it's a void value and not much point making it lazy, e.g. it's not expensive to compute; it doesn't help break a two-phase initialisation loop, so why do it?
In Kotlin variables not declared as nullable or lateinit must be initialized in the constructor (or init). I am trying to do this like this:
class Foo{
var foo:myType
init{
complicatedFooInit()
}
fun complicatedFooInit(){
foo = //a whole bunch of code here
}
}
I still get the Property must be initialized or declared abstract error. You can easily reproduce this by making myType an Int and just setting it equal to 3 in the complicatedFooInit function. Obviously there are ways around this (just not making it a function, having complicatedFooInit return myType and setting foo equal to it, etc.). My question is, why is the above code invalid? Or is it valid with some tweaking?
Compiler have no idea what's going on inside complicatedFooInit() function (cause it may be too burden to investigate all execution flow of potentially dozens nested functions called from init block). He wants to see initialization directly inside init block. So you need to make complicatedFooInit() return desired value:
class Foo {
var foo: myType
init {
foo = complicatedFooInit()
}
fun complicatedFooInit(): myType {
//a whole bunch of code here
return ...
}
}
Actually, in this case property initialization on declaration site will be more concise (no need for init block at all):
var foo: String = complicatedFooInit()
Consider also that you can have multiple init blocks, so if you want to extract some part of initialization into a function, e.g.
init {
complicatedFooInit()
complicatedBarInit()
}
I would replace each function by a separate init block:
// comment about foo initialization
init {
// body of complicatedFooInit()
}
// comment about bar initialization
init {
// body of complicatedBarInit()
}
The problem is that you can't pass arguments to init blocks; but any arguments you'd pass to complicatedFooInit can only depend on the primary constructor parameters, and so can be set up in the beginning of the corresponding init block.
You also can't call the same function twice with different parameters,
init {
complicatedFooInit(true)
complicatedFooInit(false)
}
but you wouldn't want to anyway, because it would initialize foo twice; unless complicatedFooInit initializes different variables depending on its arguments, but it would make the compiler's burden mentioned in Михаил Нафталь's answer much worse!
In Swift 3 the dispatch_once function was removed and the migration guide suggests to use initializing closure:
let myGlobal = { … global contains initialization in a call to a closure … }()
_ = myGlobal // using myGlobal will invoke the initialization code only the first time it is used.
I'd like to access 'self' instance variables from within the initializing closure like so:
class SomeClass {
var other = SomeOtherClass()
let initialize: () = {
// self.other - this doesn't work, complains about unresolved identifier 'self'
// how to access self.other here?
} ()
func doSomething() {
// initialize will only be called once
initialize
}
}
Why is 'self' not accessible in the closure and how can make it to be?
This quoted example of the Migration Guide is misleading because it's related to a global variable.
The closure of a instance let constant is called (once) immediately when the class is initialized. That's the reason why it cannot use other variables declared on the same level.
What you can do is to initialize initialize (the variable name is not the best one ;-) ) lazily. The closure is also called only once but – as the guide describes – only the first time (when) it is used.
class SomeClass {
let other = SomeOtherClass()
lazy var initialize : () = {
let test = self.other
test.doSomething()
}()
func doSomething() {
// initialize will only be called once
_ = initialize
}
}
When an instance of the 'SomeClass' class is created, it will first create all of the variables and constants on that instance. During this time, self may not be fully initialised, because it may be halfway through setting up. Because of this, self is not available until after the initialisation step has completed.
In the example, they were talking about a global variable which has no concept of self, or a static constant on the class which also has no concept of self.
If it needs to be an instance method/variable you could:
a) make it a lazy var like
lazy var initialise : ()->Void = {
return {
// can access self here
}
}()
which will be created the first time you call it, rather than during initialisation. Of course you lose the constant that way, and you have to store the closure which is wasteful since you're only executing it once.
b) put the code inside of an init method:
init() {
// if your class doesn't have a super class, you can access self.other here.
// If it does have a super class (like NSObject) you must first call super.init() here to complete the initialisation.
// This can only be done after all other variables have been set.
}
Please excuse me for the poor title. Will update it if something better comes in mind.
Tested on: Xcode Version 7.2.1 (7C1002)
I want to take advantage of Swift's lazy stored properties to compute the value of a property while in a "background" queue before accessing it from the main queue.
Here is a class defining a lazy stored property
class Cache {
lazy var heavilyComputational = {
return 42
}()
}
This is an example usage
dispatch_async(dispatch_queue_create("com.qnoid.compute", DISPATCH_QUEUE_CONCURRENT)){
let cache = Cache()
let _ = cache.heavilyComputational
dispatch_async(dispatch_get_main_queue()){
debugPrint(cache.heavilyComputational)
}
}
That works.
Warning aside, IMO the intent is not clear.
A lazy property is lazily computed yes but in this case, the "where", "when" and "why" are equally important and not as clear.
Tried to clarify intent by being "clever" using a struct like so
struct Compute {
var function: () -> Void {
didSet{
function()
}
}
}
dispatch_async(dispatch_queue_create("com.qnoid.compute", DISPATCH_QUEUE_CONCURRENT)){
let cache = Cache()
Compute {
cache.heavilyComputational
}
dispatch_async(dispatch_get_main_queue()){
debugPrint(cache.heavilyComputational)
}
}
but the compiler "outsmart" me by removing the instruction (AFAICT) since the Compute instance isn't used. FWIW, this is on the Debug configuration and I can only assume on Release it will be even more aggressive.
For comparison, this works as expected (*not the didSet call)
dispatch_async(dispatch_queue_create("com.qnoid.compute", DISPATCH_QUEUE_CONCURRENT)){
let cache = Cache()
let compute = Compute {
cache.heavilyComputational
}
compute.function()
dispatch_async(dispatch_get_main_queue()){
debugPrint(cache.heavilyComputational)
}
}
but by that time, the whole purpose is defeated.
1. Have I misunderstood something?
2. Is there a native construct to allow for something like this in Swift?
3. If not, is there a way to rewrite this code so that the intent is clear?
4. Why the didSet is not called?
Sample project: https://github.com/qnoid/compute
It seems you kinda realise the problem. As far as I know, didSet won't be triggered if it's in the init method.
In your case, when you do
Compute {
cache.heavilyComputational
}
It's actually using init method of the struct to set the function property which will not trigger the didSet.
And in your second attempt, since you explicitly call the function() which will then call cache.heavilyComputational, so you trigger the lazy initialization of heavilyComputational manually. It's pretty much equivalent to your original (without the Compute struct) method.
To make your struct works without calling the function, you have to do some hacks.
struct Compute {
var function: () -> Void = {} {
didSet{
function()
}
}
init(function: () -> Void) {
setFunction(function)
}
private mutating func setFunction(function: () -> Void) {
self.function = function
}
}
So then you can just do
Compute {
cache.heavilyComputational
}
For further improvement, I'll have to think about it.
I believe I have found a simple answer to this.
struct Compute {
init(f: () -> Void) {
f()
}
}
Happy with that answer for question 3, the rest remain. Tho, worry I might be bitten by some future compiler optimisation.
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.