Cool, thanks. I also realize now that the cost of copying the value in most cases is pretty minimal - my example of an int was dumb, what I was really using was dynamic arrays, but 40 bytes... not a big deal. Still, with large structs as a value, I could see this being troublesome.
The language is surprisingly solid for being so new and unfinished, but playing around I've noticed a few things that might be worth bringing to your attention. First, type-parameterized functions don't seem to import properly - I had a simple function:
| typename :: proc(T: type) -> string {
return fmt.aprint(type_info(T));
}
|
and it worked while in the main file, but when I moved it out to another file and imported that it gave me an error that the name wasn't defined. Other functions in that file were all good, the type parameterization seemed to be key.
Another thing is that there doesn't currently seem to be any built-in way to remove a value from a dynamic array. I've solved that problem for myself, but the solution is less than ideal - although once you have implicit type parameters, it would be much cleaner to implement:
| remove :: proc(T: type, array: ^[dynamic]T, index: int) #inline {
if len(array) > 0 && len(array) > index {
copy(array^[index..<len(array)-1], array^[index+1..]);
tmp := transmute(raw.DynamicArray, array^);
tmp.len -= 1;
array^ = transmute([dynamic]T, tmp);
}
}
|
Last, a problem I find utterly mystifying, that maybe has to do with bypassing some Windows initialization stuff in the runtime - reading from the console is impossible. Since there's no standard library way to read console input, I tried rolling my own. Using os.read with os.stdin, the function doesn't return when enter is pressed. If I hit ctrl-C, it works just fine and reads the input, but of course exits the program. I tried importing ReadConsoleA from kernel32.lib, and the same thing happened. Bizarre. Actually, I just tried again to verify and os.read is returning 0 bytes read, but ReadConsoleA is still working alright (not sure what changed...). Here's the full file, sorry for the length:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 | import "fmt.odin";
import "raw.odin";
import "os.odin";
import win32 "sys/windows.odin";
foreign_system_library (
"kernel32.lib" when ODIN_OS == "windows";
)
foreign kernel32 {
_read_console :: proc(h: win32.Handle, buf: rawptr, to_read: u32, bytes_read: ^i32, input_control: rawptr) -> win32.Bool #cc_std #link_name "ReadConsoleA" ---;
set_console_mode :: proc(h: win32.Handle, mode: u32) -> win32.Bool #cc_std #link_name "SetConsoleMode" ---;
}
read_console :: proc(handle: os.Handle, data: []u8) -> (int, os.Errno) #inline {
if len(data) == 0 {
return 0, os.ERROR_NONE;
}
single_read_length: i32;
total_read: i64;
length := i64(len(data));
for total_read < length {
remaining := length - total_read;
to_read: u32;
MAX :: 1<<32-1;
if remaining <= MAX {
to_read = u32(remaining);
} else {
to_read = MAX;
}
e := _read_console(win32.Handle(handle), &data[total_read], to_read, &single_read_length, nil);
if single_read_length <= 0 || e == win32.FALSE {
err := win32.get_last_error();
return int(total_read), os.Errno(err);
}
total_read += i64(single_read_length);
}
return int(total_read), os.ERROR_NONE;
}
readline :: proc(max_bytes: int = 16) -> string {
line := raw.String {
data = ^u8(alloc(max_bytes)),
len = 0,
};
if bytes, err := read_console(os.stdin, slice_ptr(line.data, max_bytes)); err != os.ERROR_NONE || bytes == 0 {
for i in line.len..line.len+bytes{
char := (line.data + i)^;
if char == '\r' || char == '\n' {
bytes = i;
break;
}
}
line.len += bytes;
} else {
if err != os.ERROR_NONE {
fmt.println("Error:", err);
}
}
return transmute(string, line);
}
main :: proc() {
for {
input := readline();
defer free(input);
match input {
case "help":
fmt.println("There is no help for you.");
case "echo":
fmt.println("Echo-cho-o-o");
case "exit":
break;
case:
fmt.printf("{%s}\n", input);
}
}
}
|
The read_console function is basically copy and pasted from os_windows.odin's read, but I fixed what seems to be a bug - line 37 above, in os.read you were returning Errno(e) instead of Errno(err).
Also, I find it kind of strange that after pressing ctrl-C, the program continues, gets the input, prints it, and then exits rather than continuing the for loop in main. I would think it would either exit immediately, or finish executing.
EDIT: Oops, the reason os.read doesn't work is because line 51 is expecting err != os.ERROR_NONE instead of err == os.ERROR_NONE. With ReadConsoleA, ctrl-C returns os.ERROR_OPERATION_ABORTED, with ReadFile that doesn't happen. Still though, the rest is valid.