Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: Go 2: defer/init methods for structs #21737

Closed
EdSaleh opened this issue Sep 1, 2017 · 18 comments
Closed

proposal: Go 2: defer/init methods for structs #21737

EdSaleh opened this issue Sep 1, 2017 · 18 comments
Labels
FrozenDueToAge LanguageChange Suggested changes to the Go language Proposal v2 An incompatible library change
Milestone

Comments

@EdSaleh
Copy link

EdSaleh commented Sep 1, 2017

Hello,
I would like to propose defer and init functions for structs that are applied when a struct is created.
Examples:

type MyStruct struct {
id int
}

func (ms *MyStruct) defer(returned boolean) {
//...code
}

func (ms *MyStruct) init(params ....) {
//...code
}

All the compiler would do is:

  1. Detect if struct has init() and defer() function members associated with it.
  2. If Yes, execute them right after struct variable declaration.
  3. Detect whether it's returned, if yes, defer defer(true) else defer defer(false)
    Example:

var myStruct= MyStruct{}
OR
var myStruct= MyStruct{}(params)

OR Even
var myStruct = MyStruct()

Maybe MyStruct{}() Or MyStruct() is forced by compiler when the struct is implementing init() and/or defer() methods while MyStruct{} for when they are not implemented.

Would be done in the compiler as:

var myStruct= MyStruct{}
myStruct.init(params)
defer myStruct.defer(returned)
//provided that myStruct has init() and defer() functions associated with it of course.

Rust has a similar way of doing this also.

OR other forms:

defer func (ms *MyStruct) {
//...code
}
func (ms *MyStruct)() {
//...code
}

OR all just through structs

type MyStruct struct {
init func()=func(){}
id int =0
defer func()=func(){}
}

Thank You,

@gopherbot gopherbot added this to the Proposal milestone Sep 1, 2017
@EdSaleh EdSaleh changed the title Proposal: defer functions Proposal: defer/init functions Sep 1, 2017
@EdSaleh EdSaleh changed the title Proposal: defer/init functions Proposal: defer/init functions for structs Sep 1, 2017
@dsnet dsnet added LanguageChange Suggested changes to the Go language v2 An incompatible library change labels Sep 2, 2017
@davecheney
Copy link
Contributor

davecheney commented Sep 2, 2017 via email

@EdSaleh
Copy link
Author

EdSaleh commented Sep 2, 2017

@davecheney edited.

@davecheney
Copy link
Contributor

@medozs thank you for your edit. I'm sorry that I don't know what this proposal is proposing.

Can you please explain what you cannot do today, and how this proposal would allow you to do the thing.

Thanks

@EdSaleh
Copy link
Author

EdSaleh commented Sep 2, 2017

@davecheney My proposal is similar constructor/destructor for objects in OOP. Instead of calling the constructor method init() inside our function every time to initialize our structure values, and instead of calling the defer function with the keyword defer inside function, I am proposing that all this is done automatically when strict is declared in function.

@cznic
Copy link
Contributor

cznic commented Sep 2, 2017

When should be the destructor called? Should be running the destructor guaranteed to eventually occur? How's the destructor different wrt the existing finalizers?

@EdSaleh
Copy link
Author

EdSaleh commented Sep 2, 2017

@cznic
My proposal is:
Instead of manually doing
myStruct.init()
defer myStruct.defer()
I propose that these methods to be applied automatically as soon as struct object is created.
So just:
var myStruct= MyStruct{} would apply these defer() and init() functions.

@davecheney
Copy link
Contributor

davecheney commented Sep 2, 2017 via email

@EdSaleh
Copy link
Author

EdSaleh commented Sep 2, 2017

@davecheney As soon as struct variable is created in a function or through function parameters. defer() function would be deferred, meaning it will be finally executed at the end of the function struct variable is declared in.

@davecheney
Copy link
Contributor

davecheney commented Sep 2, 2017 via email

@EdSaleh
Copy link
Author

EdSaleh commented Sep 2, 2017

@davecheney These things are up to programmer to analyze and decide. GC or programmer can take care of things escaping as well. There shouldn't be return values associated with init() or defer() functions. Basically all the compiler should do is:

  1. Detect if struct has init() and defer() function members associated with it.
  2. If Yes, execute them right after struct variable declaration.
    Example:

var myStruct= MyStruct{}

would be done in the compiler as:

var myStruct= MyStruct{}
myStruct.init()
defer myStruct.defer()
//provided that myStruct has init() and defer() functions associated with it of course.

@davecheney
Copy link
Contributor

davecheney commented Sep 2, 2017 via email

@EdSaleh
Copy link
Author

EdSaleh commented Sep 2, 2017

@davecheney My proposal is not concerned with these values. It's just concerned with executing init() and defer() functions automatically instead of manually. init() at the beginning of struct var declaration, and deferring defer() function to be executed as the end of function.

@bcmills
Copy link
Contributor

bcmills commented Sep 6, 2017

init functions are not needed in Go: idiomatic New functions work nicely, and struct literals are often even better. (See https://golang.org/doc/effective_go.html#composite_literals.)

init functions are often used in C because there is otherwise no way to construct stack-allocated values containing internal pointers, and in the no-exceptions dialect of C++ because there is otherwise no way to surface errors from the constructor. Thankfully, Go does not suffer from either of those problems.

An idiomatic version of your example in Go would look more like:

s := NewMyStruct(params)
defer s.Close()

@pcostanza
Copy link

Destructors are generally problematic in garbage-collected languages, since a garbage collector usually doesn't give any guarantees when unreachable objects are freed, or whether they are freed at all. (A program may exit before a particular unreachable object is freed.) It may be something to put in the unsafe package, but I believe it shouldn't be part of the language proper.

C++ is either manually managed or relies on reference counting (via smart pointers), so the case there is very different.

@ianlancetaylor ianlancetaylor changed the title Proposal: defer/init functions for structs proposal: Go 2: defer/init functions for structs Sep 9, 2017
@bcmills
Copy link
Contributor

bcmills commented Sep 11, 2017

@pcostanza

a garbage collector usually doesn't give any guarantees when unreachable objects are freed

I think you are confusing destructors with finalizers. Go already has finalizers, and they have exactly the problems you mention.

The way I read this proposal, it is about destructors that run at the end of the scope in which a variable is declared, rather than when the underlying value becomes reachable. Those have their own problems (namely, use-after-destruction bugs), but those problems are more closely related to data races and typestate bugs than they are to finalizers.

Note that defer is already prone to the same sorts of bugs as destructors: the main advantages of the explicit defer are that calls can refer to other variables from the surrounding scope, and that the explicit defer statement signals to the reader to pay extra attention to the risk of typestate bugs.

@creker
Copy link

creker commented Sep 11, 2017

This looks more like IDisposable in C# where it guaranteed that Dispose method will be called at the end of usage block. Extremely useful in C# and doesn't conflict with GC. But does introduce a problem with use-after-destruction, which throws ObjectDisposedException

@Spriithy
Copy link

I have a problem with this feature as I don't see the point of having a defer method on structure types. I mean, this really looks like the C++  std::unique_ptr<T> wrapper type. What are the benefits of this over the builtin GC step that would free the struct when needed ?

Would you not rather have the defer method being called upon Garbage Collection of such a struct ?

@griesemer griesemer changed the title proposal: Go 2: defer/init functions for structs proposal: Go 2: defer/init methods for structs Mar 20, 2018
@ianlancetaylor
Copy link
Contributor

This is a partial addition of C++ constructors and destructors to Go. It's not sufficient; there is a reason that C++ also has move constructors and assignment constructors. It's also incomplete: when does the destructor run for values that are on the heap? That is to say, for values allocated using new? In C++ the problem is simpler because there is no garbage collection and because the lifetime of values is controlled explicitly by the program. In Go the lifetime may change if the address is taken or depending on when garbage collection runs.

Proposal declined.

@golang golang locked and limited conversation to collaborators Mar 20, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge LanguageChange Suggested changes to the Go language Proposal v2 An incompatible library change
Projects
None yet
Development

No branches or pull requests

10 participants