Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am intrigued with a question that an engineer at the company I work at asked me, about whether or not it is better to have a single function that traverses an array and tests two conditions or to have two functions, with a single condition each.
I came here to ask you guys if my rationale is wrong or not.
The code was something near this:
response := ListObjectsFromS3(bucket)
var filteredEmptyObjectsArray = utils.FilterEmptyObjects(response)
var filteredNonJson = utils.FilterNonJson(filteredEmptyObjectsArray)
With each function being:
func FilterEmptyObjects(arrayToFilter []*Object) []*Object {
var filteredArray []*Object
for _, object := range arrayToFilter {
if *object.Size > 0 {
filteredArray = append(filteredArray, object)
}
}
return filteredArray
}
func FilterNonJson(arrayToFilter []*Object) []*Object {
var filteredArray []*Object
for _, object := range arrayToFilter {
if strings.HasSuffix(*object.Key, ".json") {
filteredArray = append(filteredArray, object)
}
}
return filteredArray
}
Please pardon the repetition in the code above. It is meant as a toy example.
I don't know exactly how does Go optimizes this code, but I was thinking it might "squash" both functions into something like this - of course, not in Go code but the generated machine code would be equivalent to this:
func FilterSquashed(arrayToFilter []*Object) []*Object {
var filteredArray []*Object
for _, object := range arrayToFilter {
if strings.HasSuffix(*object.Key, ".json") && *object.Size > 0 {
filteredArray = append(filteredArray, object)
}
}
return filteredArray
}
And the code of the response - also not really in Go code, but the compiler would generate a machine code equivalent to something like this:
response := utils.FilterSquashed(ListObjectsFromS3(bucket))
The point is that when I made the objdump of the optimized code and the non-optimized one, both had the functions separated and would have a CALL to each function. So, I'm trying to understand what is the depth of optimization that is currently possible or that Go compiler decided to stick with.
Let me know your thoughts
The "squashed" code you show is not equivalent to the original code. The basic rule of code optimization is that the effects of the optimized and non-optimized code must be the same but in your example, you have two functions that apply different logic to filter a list, and a third function that would apply a third kind of logic that in this particular case would give you the composition of the two original functions, but not in the general case. So in short: no compiler would do what you are asking for in this case, because the semantics are different.
There may be cases when some functions are inlined the compiler might discover more optimizations, but I don't see how your example might benefit from inlining.
Related
// reflect/value.go
func ValueOf(i interface{}) Value {
if i == nil {
return Value{}
}
// TODO: Maybe allow contents of a Value to live on the stack.
// For now we make the contents always escape to the heap. It
// makes life easier in a few places (see chanrecv/mapassign
// comment below).
escapes(i)
The code above is the source code of Value.go in golang, and the comment above the escapes(i) shows that each time we call the ValueOf function, the i will escape to the heap, that's why? Namely, how to explain the It makes life easier in a few places?
I am still learning go, so I can't describe more, that's why a community wiki answer. But here's what excerpted note says (note above the chanrecv function):
Note: some of the noescape annotations below are technically a lie,
but safe in the context of this package. Functions like chansend
and mapassign don't escape the referent, but may escape anything
the referent points to (they do shallow copies of the referent).
It is safe in this package because the referent may only point
to something a Value may point to, and that is always in the heap
(due to the escapes() call in ValueOf).
Also see:
// Dummy annotation marking that the value x escapes,
// for use in cases where the reflect code is so clever that
// the compiler cannot follow.
func escapes(x interface{}) {
if dummy.b {
dummy.x = x
}
}
var dummy struct {
b bool
x interface{}
}
I hope, this will be helpful.
Code I'm exploring:
type Stack struct {
length int
values []int
}
func (s *Stack) Push(value int) {
// ...
}
func (s *Stack) Pop() int {
// ...
}
func (s *Stack) Length() int {
return s.length
}
Methods Push and Pop change the length field in Stack struct. And I wanted to hide this field from other files to prevent code like stack.length = ... (Manual length change). But I was need to have ability to read this field, so I added getter method - Length.
And my question is:
Shouldn't stack.Length() become slower than stack.length, because it is a function call? I have learnt assembler a bit and I know how many operations program should do to call a function. Have I understand right: By adding getter method stack.Length() I protected those who use my lib from bad usage but the cost of it - program's performance? This actually concerns not only Go.
Shouldn't stack.Length() become slower than stack.length, because it is a function call?
Objection! Assumes facts not in evidence.
Specifically:
Why do you think it is a function call? It looks like one, but actual Go compilers will often expand the code in line.
Why do you think a function call is slower than inline code? When measuring actual programs on actual computers, sometimes function calls are faster than inline code. It turns out the crucial part is usually whether the instructions being executed, and their operands, are already in the appropriate CPU caches. Sometimes, expanding functions inline makes the program run more slowly.
The compiler should do the inline expansion unless it makes the program run more slowly. How good the compiler is at pre- or post-detecting such slowdowns, if present, is a separate issue. In this particular case, given the function definition, the compiler is almost certain to just expand the function in line, as accessing stack.length will likely be one instruction, and calling a function will be one instruction, and deciding the tradeoff here will be easy.
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I am trying to use composite literal with maps but unable to use it as it shows some error.
please find the code below.
I am a newbie to Golang and perhaps have some less understanding about composite literals.
type Assessment struct{
StructuringForce map[string][]StructuringForce
}
type StructuringForce struct {
Principles map[string][]Capabilities
}
type Capability struct {
}
c1 := Capability{}
a1 := Assessment{
StructuringForce : map[string][]StructuringForce{
"Information Systems" , []StructuringForce{
StructuringForce{
Principles : map[string][]Capabilities{
"Integration of IT Services" ,[]Capabilities{
c1,
},
},
},
},
},
}
while constructing "a1" with composite literals I get "Missing key in map literals error".
But i can see that i have added keys.
As Volker pointed out, make cannot be used with literals. In your case it can either be:
make(map[string][]StructuringForce)
or
map[string][]StructuringForce{}{}
Secondly, for golang map, it's using : to separate the key-value, so it should be like:
a := map[string]string{
"foo": "bar",
}
Thirdly, you don't have Capabilities defined, so I suppose you're trying to do Capability.
To sum up, the entire thing in the main func should look like:
c1 := Capability{}
a1 := Assessment{
StructuringForce: map[string][]StructuringForce{
"Information Systems": []StructuringForce{
StructuringForce{
Principles: map[string][]Capability{
"Integration of IT Services": []Capabilities{
c1, // missing comma here as well
},
},
},
},
},
}
However, based on what you pasted, I would suggest you start from something straightforward to get started with the syntax and how to compose a map, like Go By Examples.
Another suggestion is that you can wrap the running code in main func when posting a SO question, which will make reproducing the issue a lot easier and more understandable to others who try to help.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I often write code such as the following
bool myFunct (...)
{
if (something)
{
return false;
}
// .... more code ....
}
The alternative is
bool myFunct (...)
{
if (something)
{
return false;
}
else
{
// .... more code ....
}
}
Of course, that else block is unnecessary, because the early return means that reaching the else statement in the first place is the equivalent of being inside it. Then there's the fact that, to make the compiler happy, I often have to change the structure of the 2nd implementation to
bool myFunct (...)
{
bool retval = true;
if (something)
{
retval = false;
}
else
{
// .... more code ....
}
return retval;
}
which is extra code and looks stupid. My question is, what do the governing authorities and priests say about this type of situation?
Not only it is OK, it is even encouraged in Spartan Programming. According to Spartan Programming - shorter and simpler code is better, and you achive it (among other ways) by fast terminations and avoiding else statements when possible
Under minimizing use of control:
(2) Simplifying conditionals with early return.
(4) Simplifying logic of iteration with early exits (via
return, continue and break statements).
P.S. It seems #Jeff Atwood also likes the spartan programming way
Of course. You're basically writing a guard condition that will stop you trying to perform unnecessary logic. It's fine.
Like many things, it's personal preference, but I prefer to see code written like your second example for simple cases, and the third example for more complex cases. That doesn't mean any are wrong, though.
There's nothing technically wrong with having an else clause for an if clause that does not terminate naturally (e.g., has a return or throw statement), it's just useless.
Several style guidelines argue against it (and several IDE and analysis tools may produce warnings to support these guidelines), but ultimately, it's just a preference.
The 2nd example looks fine to me because, if the code in the first statement is updated like below, it'll prevent unexpected behavior :
bool myFunct (...)
{
if (something)
{
// ... stuff
if (something_else) return false;
}
else
{
// .... more code ....
}
}
If you look at the image package here http://golang.org/src/pkg/image/image.go you can see that the implementation of Opaque() for every image does the same thing, differing only in the pixel-specific logic.
Is there a reason for this? Would any general solution be less efficient? Is it just an oversight? Is there some limitation (I cannot see one) to the type system that would make a polymorphic [was: generic] approach difficult?
[edit] The kind of solution I was thinking of (which does not need generics in the Java sense) would be like:
type ColorPredicate func(c image.Color) bool;
func AllPixels (p *image.Image, q ColorPredicate) bool {
var r = p.Bounds()
if r.Empty() {
return true
}
for y := r.Min.Y; y < r.Max.Y; y++ {
for x := r.Min.X; x < r.Max.X; x++ {
if ! q(p.At(x,y)) {
return false
}
}
}
return true
}
but I am having trouble getting that to compile (still very new to Go - it will compile with an image, but not with an image pointer!).
Is that too hard to optimise? (you would need to have function inlining, but then wouldn't any type checking be pulled out of the loop?). Also, I now realise I shouldn't have used the word "generic" earlier - I meant it only in a generic (ha) way.
There is a limitation to the type system which prevents a general solution (or at least makes it very inefficient).
For example, the bodies of RGBA.Opaque and NRGBA.Opaque are identical, so you'd think that they could be factored out into a third function with a signature something like this:
func opaque(pix []Color, stride int, rect Rectangle) bool
You'd like to call that function this way:
func (p *RGBA) Opaque() bool {
return opaque([]Color(p.Pix), p.Stride, p.Rect)
}
But you can't. p.Pix can't be converted to []Color because those types have different in-memory representations and the spec forbids it. We could allocate a new slice, convert each individual element of p.Pix, and pass that, but that would be very inefficient.
Observe that RGBAColor and NRGBAColor have the exact same structure. Maybe we could factor out the function for just those two types, since the in-memory representation of the pixel slices is exactly the same:
func opaque(pix []RGBAColor, stride int, rect Rectangle) bool
func (p *NRGBA) Opaque() bool {
return opaque([]RGBAColor(p.Pix), p.Stride, p.Rect)
}
Alas, again this isn't allowed. This seems to be more of a spec/language issue than a technical one. I'm sure this has come up on the mailing list before, but I can't find a good discussion of it.
This seems like an area where generics would come in handy, but there's no solution for generics in Go yet.
Why does Go not have generic
types?
Generics may well be added at some
point. We don't feel an urgency for
them, although we understand some
programmers do.
Generics are convenient but they come
at a cost in complexity in the type
system and run-time. We haven't yet
found a design that gives value
proportionate to the complexity,
although we continue to think about
it. Meanwhile, Go's built-in maps and
slices, plus the ability to use the
empty interface to construct
containers (with explicit unboxing)
mean in many cases it is possible to
write code that does what generics
would enable, if less smoothly.
This remains an open issue.