Oddbean new post about | logout
 Minor coding convention #rant.

Types should be in the declaration, not the assignment. Inferred types are difficult to read and don't add that much more verbosity imo.

You aren't assigning a type to variable, you are declaring a variable of a type. The compiler MUST know the data type (and it size more specifically) to allocate registers or stack memory. I should be able to look down the left hand side of the file for the variable name and see it's data type. 

Personally, I don't even like mixing declarations and assignments, I write in strict C89 standard for my own sanity. Deceleration resides as the first statements and assignment happens later. I wonder if this is leaking from the "immutability movement"
 
 Can you provide an example snippet? 
 ``` C++
auto p = MyType();
... 20+ lines 
// what tf is p? even if it's named correctly it should be named for it's purpose, mutually exclusive to it's type. 
```

Same with C#
``` C#
var p = new MyType();
```

My preferred style in all C-ish languages

```C
void Foo(void)
{
  //Declaration, tells me and my compiler what memory will be in use throughout the function
  int myInt, myInt2;
  int* myPtr;

  //Assignment is it's own statment
  myInt = 0x01;
  myInt2 = 0x02;

  // easily cleanup or destroy memory if needed because I know at the top what's been created
}
```
 
 i remember the olden days of C... declare before use pattern, even was (is?) required for functions, in order to call them they must be further up the page

i've got so used to the Wurth style returns to the right of the function and receivers to the left though, and do you really need to explicitly state that a function has no parameters like that? 
 Yes C89 enforces declare before assign. They must be completely separate statements ';'. 

>and do you really need to explicitly state that a function has no parameters like that
For C89 and -pedantic, yes. Some compilers even in C89 mode don't care, GCC will complain though. I think the Windows cl doesn't care though.  
 i'm just quite content over here with my language with implicit things that are implicit 
 also with the file-level non-imperative declaration (though it does execute functions in var and init() in top to bottom order, that can be troublesome sometimes but it is what it is, and globals are bad mkay) 
 "Moisturized, in my lane" 
 yeah, i was having a bad afternoon when suddenly somehow it seemed like the event store wasn't keeping tags but no... it wasn't decoding tags... and it seems i have retained the memory leak bug fix as well so i'm feeling very moisturised 
 Any idea what the issue was? It's been a saga my friend 
 yeah, it wasn't growing the arrays to fit what was being put into them

still got another glitch in here somewhere, probably a regression... again a forever loop in the database query code lol

idk even how it's happening, probably me putting the wrong direction <> in somewhere 
 i think i found it... i switched to collecting the found events in a map (key/value hash table) and i was checking the limit size based on the result variable which isn't populated until after all the event keys are retrieved

i think this will fix it

it's that kind of forever loop where your termination condition is incorrect and it keeps looping because the condition doesn't update to reflect the state of execution 
 btw, the point of using the maps is it allows me to automatically deduplicate in case of clients sending filters with repeating elements that yield the same event again... which probably can happen, so best to mitigate it 
 Ok I see thanks. So, my security code review eyes would want to make a comment on this style and say that declaration should go with assignment.

Because what can happen is that the default assignment is sometimes used mistakenly and results in undefined behavior.

Obviously not an issue if you follow up with the assignments as you did, but just stating an observation. 
 True but I think even -Wall -Werror on all the compilers I've worked with whine about use before assignment. 

If you have a function with 40+ lines it's easy to miss where a variable may have been declared. I use unconditional jumps often, so I like to see where variables are declared incase I need to do something with them. 

If my variables are declared immediately, I always know they are accessible no matter where I jump to in the function. 

But I definitely get the UB of default values. I try to assign variables as the first statement's if possible, and manually assign default/failing values for this reason.  
 Yeah, -wall -werror fixes many problems. 
 Actually when using Visual Studio the intellisense even freaks out with accessing structure members after declaration (before assignment) which is proper behavior in C but I guess frowned upon in C++ 
 yeah, go's `:=` operator often gets overused but it's neat for constructor functions, notably maps must be dynamically allocated so if a complex type has them it must have a constructor/initializer

i personally have some style rules i try to stick to, similar to yours:

- always give a name to return values that helps you understand what the function does at a glance - this one i had a brief argument about with Ian Lance Taylor of all people

- prefer to use a "var" declaration of a variable if the type is a value or slice (both don't need initialization) and the reason is that it allows you to inline a function call with assignment to its return value variables and most usually an error check clause, because most of teh time in Go you should return an error unless there is no error case for the function (such as those constructors, even then sometimes they do have failure modes, entropy consuming especially always makes me crazy what do i do if the system entropy is ded? lol, doesn't seem like a case i can handle, probably should just panic instead of error because all bets are off with /dev/random no workee 
 lol. 

Yeah I do and don't like the tuple like returns of GO. I appreciate error codes over exceptions, but since I know CPUs only have one return value register (usually) I know only that sized result can be returned, anything else has to happen on the stack, or heaven forbid the heap. So the compiler is hiding things from me and I don't like that XD 
 go doesn't let you use tuples outside of function returns, and it's based on two things, fail fast, and the problems of variants (union types) versus interfaces (which contain type information that can be accessed safely)

i feel like they went crazy with the wrapping of errors and i prefer log-at-the-site with code locations but sometimes the logs get noisy and i find myself wanting to hide them with minimal effort but it doesn't really work out so well... i did start writing an interface for logging that included dynamic filtering and subsystem filtering but it wasn't critical to my work so i let it go... but something i'd love to have at some point again 
 also should just point out that C allows tuples as parameters, that was where the Go design came from... Go also has variadic parameters... in theory the last parameter of a return could be variadic too but generally you'd just use a slice, dynamic arrays are neat like that... the value is the array header, so appending to it can run an allocation/initialization behind the scenes (and in Go all values are zeroed by default, one of C's big bug sources) 
 I use goto everywhere except in @Michael J s code XD. Even in C# which makes people upsetty. I paid for all of the features I'm going to use them XD 
 goto is great for anything involving state machines

any other option makes complications

STATE = something
switch STATE { case "beforeBracket":...

you get the picture

with goto you just jump to that location, and done 
 just should point out that in Go, the use of labels and break/continue is basically idiom, and has to be if you have for switches or for loops inside other switches or for loops because those address the local scope and you need labels to break out of outer scopes

also in Go the for statement is a lot more flexible than almost any other language, it does all the things, the do whiles, the regular 3 clause, there is now even a simple zero to X syntax for it

and further, scope can be a problem, but also has benefits - you can shadow variables inside if, for and switch statements - ie, same name, new variable... i consider that to be a no-no though, i only "scope shadow" inside goroutines which are essentially completely independent functions even if they are bounded inside another function 
 yeah, Go has goto, and labels, like modern froms of (not line number label) BASIC

they are very useful for making concise and easy to understand state machines... but they are really bad to use in any other way... generally continue/break statements jumping back to the statement at under the label or jumping to the next statement after the scope below the label (eg for loops, etc)

they are a lot cheaper than storing state on the stack especially when usually, such as parsing encoded data or text, you already have a stack being used for this use case and it complicates it to put returns on top of it when the position of execution is a more elegant way to represent the current state (essentially, in machine terms it's writing to the program counter register, which tells the CPU where to load the next instruction from

it was notoriously abused by BASIC programmers in the olden days in place of if/while/for statements

but they aren't obsolete, just have a very narrow use case 
 I will use the SomeType var = new(); statement. Again because the variable is declared as a type not 'var" like wtf is this thing. And I understand that a type can be inferred since we know the data class of the variable because it's declared XD

 
 C# has some pretty good language features in that area. 
 goto is great for anything involving state machines

any other option makes complications

STATE = something
switch STATE { case "beforeBracket":...

you get the picture

with goto you just jump to that location, and done 
 just should point out that in Go, the use of labels and break/continue is basically idiom, and has to be if you have for switches or for loops inside other switches or for loops because those address the local scope and you need labels to break out of outer scopes

also in Go the for statement is a lot more flexible than almost any other language, it does all the things, the do whiles, the regular 3 clause, there is now even a simple zero to X syntax for it

and further, scope can be a problem, but also has benefits - you can shadow variables inside if, for and switch statements - ie, same name, new variable... i consider that to be a no-no though, i only "scope shadow" inside goroutines which are essentially completely independent functions even if they are bounded inside another function 
 Funny story, at my day job we just did an integration with this service that is essentially a state machine over a network.  We call an API to create a thing, but any substantive changes to the thing cause the creation of a new instance with a new ID.

It drove my team nuts for a bit because the IDs we were using to reference objects over the network weren't behavior quite like we expected. 
 yep, state machines are very fun to debug