patterngoMinor
Subnetting calculator in Go
Viewed 0 times
subnettingcalculatorstackoverflow
Problem
Whenever I try to learn a new language, I write a subnetting calculator. Here's my attempt with Go.
In particular, I think I'm not writing idiomatic Go, as well as abusing
My math should be correct, although I might have goofed when trying to translate JavaScript's number types into Go's C-esque versions.
Also, I know I should do some error-checking on the inputs (e.g. seeing if I get a logical IP instead of a string like "cat", but that'll come once I learn how to write correct Go ;))
```
package main
import (
"flag"
"fmt"
"math"
"os"
"strconv"
"strings"
)
const SIXTY_FOUR_BITS uint64 = 18446744073709551615
const MAX_BIT_VALUE int = 32
const MAX_BIT_BIN uint64 = 255
func main() {
var pf uint64
var unpack_pf uint64
flag.Parse()
if len(flag.Args()) == 0 {
flag.Usage()
os.Exit(1)
}
var ip_address string = flag.Args()[0]
var netmask = flag.Args()[1]
var ip_arr []string = strings.Split(ip_address, ".")
var sm_arr []string = strings.Split(netmask, ".")
pf, _ = strconv.ParseUint(netmask, 10, 32)
if len(sm_arr) == 1 {
if pf 32 {
pf = host_pf(pf)
unpack_pf = unpack_int(pf)
sm_arr = strings.Split(int_qdot(unpack_pf), ".")
netmask = strings.Join(sm_arr, ".")
}
if pf == 0 {
panic("Cannot have netmask >24&MAX_BIT_BIN, 10)
var x string = strconv.FormatUint(integer>>16&MAX_BIT_BIN, 10)
var y string = strconv.FormatUint(integer>>8&MAX_BIT_BIN, 10)
var z string = strconv.FormatUint(integer&MAX_BIT_BIN, 10)
var a []string = []string{w, x, y, z}
return strings.Join(a, ".")
}
func network_address(ip uint64, sm uint64) string {
return int_qdot(ip & sm)
}
func broadcast_address(ip uint64, sm uint64) string {
return int_qdot(ip | ^sm)
}
func host_pf(hn uint64) uint64 {
var x float64
if 0 >shift&mask[i]
}
return x
}
func class(bi
In particular, I think I'm not writing idiomatic Go, as well as abusing
float64(), uint64(), etc.My math should be correct, although I might have goofed when trying to translate JavaScript's number types into Go's C-esque versions.
Also, I know I should do some error-checking on the inputs (e.g. seeing if I get a logical IP instead of a string like "cat", but that'll come once I learn how to write correct Go ;))
```
package main
import (
"flag"
"fmt"
"math"
"os"
"strconv"
"strings"
)
const SIXTY_FOUR_BITS uint64 = 18446744073709551615
const MAX_BIT_VALUE int = 32
const MAX_BIT_BIN uint64 = 255
func main() {
var pf uint64
var unpack_pf uint64
flag.Parse()
if len(flag.Args()) == 0 {
flag.Usage()
os.Exit(1)
}
var ip_address string = flag.Args()[0]
var netmask = flag.Args()[1]
var ip_arr []string = strings.Split(ip_address, ".")
var sm_arr []string = strings.Split(netmask, ".")
pf, _ = strconv.ParseUint(netmask, 10, 32)
if len(sm_arr) == 1 {
if pf 32 {
pf = host_pf(pf)
unpack_pf = unpack_int(pf)
sm_arr = strings.Split(int_qdot(unpack_pf), ".")
netmask = strings.Join(sm_arr, ".")
}
if pf == 0 {
panic("Cannot have netmask >24&MAX_BIT_BIN, 10)
var x string = strconv.FormatUint(integer>>16&MAX_BIT_BIN, 10)
var y string = strconv.FormatUint(integer>>8&MAX_BIT_BIN, 10)
var z string = strconv.FormatUint(integer&MAX_BIT_BIN, 10)
var a []string = []string{w, x, y, z}
return strings.Join(a, ".")
}
func network_address(ip uint64, sm uint64) string {
return int_qdot(ip & sm)
}
func broadcast_address(ip uint64, sm uint64) string {
return int_qdot(ip | ^sm)
}
func host_pf(hn uint64) uint64 {
var x float64
if 0 >shift&mask[i]
}
return x
}
func class(bi
Solution
You have correctly noticed that this isn't extremely idiomatic. However, this code also has some issues that are completely language independent:
-
You have a large amount of magic numbers. Either explain them with a short comment, or (preferably) calculate them. Let the compiler do constant folding; don't do it yourself.
-
Your code does not have a single comment. Not having comments does not mean that your code would be self-documenting.
-
You have the tendency to declare your variables up front. Try to put the declaration as close to its first usage as possible, and try to restrict variables to the narrowest possible scope. Except in dated languages such Pascal or C 89, declaration at the top of a scope is not generally required. In fact, it is often beneficial to never declare variables without also defining them in the same statement.
-
Your variable names are quite arbitrary. Names such as
-
Your
-
If you have some kind of template in your code, try to make this template look similar to the result. In the case of your
A few Go-specific remarks beyond those issues mentioned by Yuushi:
-
If the exact size of a numeric type is relevant in your program (and this is the case here), don't use
-
If a built-in type has a special semantic meaning in your program, declare a type alias, e.g.
-
Once you have a type for your IP adresses, you can use Go's OOP features for a more elegant interface. Instead of
-
If we're already discussing that
-
You have a large amount of magic numbers. Either explain them with a short comment, or (preferably) calculate them. Let the compiler do constant folding; don't do it yourself.
-
Your code does not have a single comment. Not having comments does not mean that your code would be self-documenting.
-
You have the tendency to declare your variables up front. Try to put the declaration as close to its first usage as possible, and try to restrict variables to the narrowest possible scope. Except in dated languages such Pascal or C 89, declaration at the top of a scope is not generally required. In fact, it is often beneficial to never declare variables without also defining them in the same statement.
-
Your variable names are quite arbitrary. Names such as
w, x, y, z are unacceptable. Instead, byte1, byte2, … might be preferable, but that means you actually want a loop. Let the compiler unroll loops if it sees fit, don't do so yourself (at least without benchmarking).-
Your
main function does both general startup such as parsing arguments, and contains the main algorithm. Separate these two concerns. When you split out the algorithm in its own function, consider returning a struct instead of a large tuple of return values.-
If you have some kind of template in your code, try to make this template look similar to the result. In the case of your
write_results format string, this means splitting it up into several lines, and concatenating the string pieces to the final format. Try to limit your line length to avoid line wrapping or horizontal scrolling in your code.A few Go-specific remarks beyond those issues mentioned by Yuushi:
-
If the exact size of a numeric type is relevant in your program (and this is the case here), don't use
int or uint, but int32 or something like that. The size of int is implementation-specific and may either be 32 bit or 64 bit. (See the language spec)-
If a built-in type has a special semantic meaning in your program, declare a type alias, e.g.
type Ip4Address uint32.-
Once you have a type for your IP adresses, you can use Go's OOP features for a more elegant interface. Instead of
func hosts(bits uint64) float64 consider func (this Ip4Adress) Hosts() int.-
If we're already discussing that
hosts function: Why on earth are you working with floats when you are actually calculating a discrete value? Note that \$2^n\$ can be calculated as `1Context
StackExchange Code Review Q#64767, answer score: 6
Revisions (0)
No revisions yet.