Hello there, I'm trying to figure out a way to properly return a type of nil value but for a struct in a function.I have a function that returns a struct and error types.When it runs into an exception, I thought I could use "nil" as the return value for the struct, but the following error keeps coming up:"cannot use nil as type Item in return argument"
What would be the proper value to return for the structs when an exception occurs?
I'd appreciate your help! thanks!Here's the code:func testreturn() (Item, error) {return nil, errors.New("error")}
--
Here are two possible scenarios:if the function return a nil:func testreturn() (*Item, error) {return nil, errors.New("error")}func anotherfun() {item, _ := testreturn()// the programmer is too lazy to check error// program crash here and everyone knows that there is something wrongitem.fun()
}
Hello there, I'm trying to figure out a way to properly return a type of nil value but for a struct in a function.I have a function that returns a struct and error types.When it runs into an exception, I thought I could use "nil" as the return value for the struct, but the following error keeps coming up:"cannot use nil as type Item in return argument"
What would be the proper value to return for the structs when an exception occurs?
I'd appreciate your help! thanks!Here's the code:
func testreturn() (Item, error) {return nil, errors.New("error")}
func (q *NodeQueue) Pop() Node {
if item := q.Queue.Pop(); item != nil {
return item.(Node)
}
return nil
}
I'm not allowed to return nil.
So my only options are, change the method signature to return *Node, which I don't want, for the reasons you explained - or construct and return a "dummy" Node instance whenever there's nothing to return? That seems awfully wasteful.
So I tried this:
const EmptyNode = Node{}func (q *NodeQueue) Pop() Node {if item := q.Queue.Pop(); item != nil {return item.(Node)}return EmptyNode}
Doesn't work either.
So my best (only?) remaining option is this:
var EmptyNode = Node{}func (q *NodeQueue) Pop() Node {if item := q.Queue.Pop(); item != nil {return item.(Node)}return EmptyNode}
It doesn't taste right - the EmptyNode really should not be a variable.
For that matter, it shouldn't really exist at all - and yeah, I know, I still need to add an error value to the return statements, but... returning a mutable instance of Node, when in actuality no Node is available - it seems misleading at best, but really, it just seems... wrong.
There's no better way to solve this problem? I mean, this must be a very, very common problem?
I agree with all of that, but I'm stuck with the following:func (q *NodeQueue) Pop() Node {if item := q.Queue.Pop(); item != nil {return item.(Node)}return nil}
I'm not allowed to return nil.So my only options are, change the method signature to return *Node, which I don't want, for the reasons you explained - or construct and return a "dummy" Node instance whenever there's nothing to return? That seems awfully wasteful.So I tried this:const EmptyNode = Node{}func (q *NodeQueue) Pop() Node {if item := q.Queue.Pop(); item != nil {return item.(Node)}return EmptyNode}
Doesn't work either.So my best (only?) remaining option is this:var EmptyNode = Node{}func (q *NodeQueue) Pop() Node {if item := q.Queue.Pop(); item != nil {return item.(Node)}return EmptyNode}
It doesn't taste right - the EmptyNode really should not be a variable.
For that matter, it shouldn't really exist at all - and yeah, I know, I still need to add an error value to the return statements, but... returning a mutable instance of Node, when in actuality no Node is available - it seems misleading at best, but really, it just seems... wrong.There's no better way to solve this problem? I mean, this must be a very, very common problem?
On Monday, October 1, 2012 12:30:01 AM UTC-4, Kevin Gillette wrote:I disagree with changing the return type from a struct value to a struct pointer just to have a convenient second indicator (nil) when there is an error.1) Use the return type that makes sense when there is no error: if value copying makes sense on the struct level, please don't use a pointer. Would you use *byte just to make it nil when there's an error?2) Anyone calling a function that returns an error should be checking the error before anything else. If they're not, then as a library writer, you're not responsible for the consequences. Programmers absolutely should not be checking for the zero value of the main return type to determine if there was an "error" condition.Some good exceptions to #2 are functions like strings.Index, because not finding the string is not an "error" -- it's a legitimate response to the question of "what is the index of my substring?" (in this case, the answer is "none").
On Saturday, September 29, 2012 2:52:02 AM UTC-6, stevewang wrote:I think the underlying question is what to indicate an invalid object, so the answer is pointer.func testreturn() (*Item, error) {return nil, errors.New("error")}On Saturday, September 29, 2012 1:17:30 PM UTC+8, Ji H Park wrote:Hello there, I'm trying to figure out a way to properly return a type of nil value but for a struct in a function.I have a function that returns a struct and error types.
When it runs into an exception, I thought I could use "nil" as the return value for the struct, but the following error keeps coming up:"cannot use nil as type Item in return argument"What would be the proper value to return for the structs when an exception occurs?I'd appreciate your help! thanks!Here's the code:func testreturn() (Item, error) {return nil, errors.New("error")}
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
So my only options are, change the method signature to return *Node, which I don't want, for the reasons you explained - or construct and return a "dummy" Node instance whenever there's nothing to return? That seems awfully wasteful.
> Please don't start caring about that until (a) you have working code that is too slow/memory-intensive for your needs and (b) you have benchmarks and profiles that prove that passing around the whole struct is the bottleneck.Performance is not my first concern - I'm not trying to optimize, I just would prefer not to return meaningless dummy values, as this can cause bugs to trickle out and makes things harder to debug... I like the addition of CanPop() which makes the consumer code more semantic and guarantees early failure.
Simply return (node Node, ok bool).
--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/4yBldwsjZwo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
Then may be you should create an interface? Because anyone still can create meaningless Node instance just typingdummy := &yourpackage.Node{}
var EmptyNode = Node{}
It doesn't taste right - the EmptyNode really should not be a variable.
returning a mutable instance of Node, when in actuality no Node is available - it seems misleading at best, but really, it just seems... wrong.
There's no better way to solve this problem? I mean, this must be a very, very common problem?
--
> You can make precisely the same arguments about null pointers, thoughExcept, no, you won't get very far if you try to treat a null-pointer as a Node instance - you will get an error and an immediate stack trace that tells you where you went wrong.
Don't worry so much about making this a var. This is fairly common for types that cannot be consts. For instance, it's used for errors all over:
What's preventing someone from writing ErrWriteToConnected = foo, and screwing everything up?
That never even occurred to me, but since the language is statically-typed, yeah... huh :-)But I don't think you're suggesting that every method should (or can) be written in such as way that it would work on a nil value?
package main
import "fmt"
// A generic Queue that can hold any interface type:
type Queue struct {
head *Item
tail *Item
}
type Item struct {
value interface {}
next *Item
}
func (q *Queue) Push(value interface {}) {
item := &Item{value, nil}
if q.tail != nil {
q.tail.next = item
}
q.tail = item
if q.head == nil {
q.head = q.tail
}
}
func (q *Queue) Pop() interface{} {
if q.head == nil {
panic("the queue is empty - use CanPop() before calling Pop()")
}
value := q.head.value
q.head = q.head.next
return value
}
func (q *Queue) CanPop() bool {
return q.head != nil
}
// A custom element type and matching Queue type for it:
type Node struct {
number int
}
type NodeQueue struct {
Queue
}
func NewNodeQueue() NodeQueue {
return NodeQueue{Queue{}}
}
func (q *NodeQueue) Push(n *Node) {
q.Queue.Push(n)
}
func (q *NodeQueue) Pop() *Node {
return q.Queue.Pop().(*Node)
}
func main() {
q := NewNodeQueue()
fmt.Printf("can pop? %t\n", q.CanPop())
q.Push(&Node{0})
fmt.Printf("can pop? %t\n", q.CanPop())
fmt.Printf("pop: %d\n", q.Pop().number)
q.Push(&Node{1})
q.Push(&Node{2})
q.Push(&Node{3})
fmt.Printf("pop: %d\n", q.Pop().number)
fmt.Printf("pop: %d\n", q.Pop().number)
fmt.Printf("pop: %d\n", q.Pop().number)
fmt.Printf("can pop? %t\n", q.CanPop())
}
Okay, I struggled a bit with pointers and did some reading... apparently interfaces are always pointers to structs (?)
which makes something like *interface{} completely redundant in my case.
> If the struct (or whatever) will fit in the pointer-sized space in the interface value then that's what's in there.I see - but that's an under-the-hood optimization, right?
conceptually, I can think of interfaces as being references to structs?
and what does "WOSSNAME" mean?
func (q *Queue) Pop() interface{} {
if q.head == nil {
panic("the queue is empty - use CanPop() before calling Pop()")
}
value := q.head.value
q.head = q.head.next
if q.head == nil {
q.tail = nil
}
return value
}
I would have caught that in a unit-test most likely, but I haven't written one yet :-)
> Conceptually: not structs -- any type.right! got it, thanks :-)> not references -- copies.
copies? I don't understand - when would they get copied?
> not references -- copies.
copies? I don't understand - when would they get copied?
--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/4yBldwsjZwo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
So in your example,var t T = sdefines a new variable of an interface type, and implicitly copies the contents of s.
so if what I wanted was a reference and not copy, I would do this:var t T = &s
interesting... so structs really don't behave like objects in other languages
- your default (or in some languages your only) option is not to pass them around by reference, but to treat them just the same as any other value.
But that also means you have to pay attention though, and take care to avoid e.g. copying expensive structs, right?
I can also think of examples where copying would actually cause problems - simplest example I can think of: if you accidentally made a copy of a service object that has an internal counter, that was supposed to return the next unique number in a sequence. If you have two copies, each copy will continue counting independently from when it was copied.
In cases like those, would you need to hide the object behind an API somehow, so it can't be copied? Or is there a better way to handle that?
> Go is a strictly pass-by-value language, where 'pass' also includes assignments and expressionsI head read that, but they didn't elaborate - the big difference for me is that structs are not "objects" in the typical sense, they are actually more like "set of values" if you will (?)
I also seem to recall reading somewhere that that's not entirely true in the case of slices though, is that right? Are slice elements really values?
var t T = s
defines a new variable of an interface type, and implicitly copies the contents of s.
var t T = &s
interesting... so structs really don't behave like objects in other languages - your default (or in some languages your only) option is not to pass them around by reference, but to treat them just the same as any other value.
But that also means you have to pay attention though, and take care to avoid e.g. copying expensive structs, right?
if you accidentally made a copy of a service object that has an internal counter, that was supposed to return the next unique number in a sequence
> Go is a strictly pass-by-value language, where 'pass' also includes assignments and expressionsI head read that, but they didn't elaborate - the big difference for me is that structs are not "objects" in the typical sense, they are actually more like "set of values" if you will (?)I also seem to recall reading somewhere that that's not entirely true in the case of slices though, is that right?
Are slice elements really values?
--