osetr
osetr

Reputation: 85

zig structs, pointers, field access

I was trying to implement vector algebra with generic algorithms and ended up playing with iterators. I have found two examples of not obvious and unexpected behaviour:

  1. if I have pointer p to a struct (instance) with field fi, I can access the field as simply as p.fi (rather than p.*.fi)
  2. if I have a "member" function fun(this: *Self) (where Self = @This()) and an instance s of the struct, I can call the function as simply as s.fun() (rather than (&s).fun())

My questions are:

  1. is it documented (or in any way mentioned) somewhere? I've looked through both language reference and guide from ziglearn.org and didn't find anything
  2. what is it that we observe in these examples? syntactic sugar for two particular cases or are there more general rules from which such behavior can be deduced?
  3. are there more examples of weird pointers' behaviour?

Upvotes: 8

Views: 8018

Answers (2)

Andrew
Andrew

Reputation: 43

I first learned this syntax by going through the ziglings course, which is linked to on ziglang.org.

in exercise 43 (https://github.com/ratfactor/ziglings/blob/main/exercises/043_pointers5.zig)

// Note that you don't need to dereference the "pv" pointer to access
// the struct's fields:
//
//     YES: pv.x
//     NO:  pv.*.x
//
// We can write functions that take pointer arguments:
//
//     fn foo(v: *Vertex) void {
//         v.x += 2;
//         v.y += 3;
//         v.z += 7;
//     }
//
// And pass references to them:
//
//     foo(&v1);

The ziglings course goes quite in-depth on a few language topics, so it's definitely work checking out if you're interested.

With regards to other syntax: as the previous answer mentioned, you don't need to dereference array pointers. I'm not sure about anything else (I thought function pointers worked the same, but I just ran some tests and they do not.)

Upvotes: 2

kristoff
kristoff

Reputation: 652

For 1 and 2, you are correct. In Zig the dot works for both struct values and struct pointers transparently. Similarly, namespaced functions also do the right thing when invoked.

The only other similar behavior that I can think of is [] syntax used on arrays. You can use both directly on an array value and an array pointer interchangeably. This is somewhat equivalent to how the dot operates on structs.

const std = @import("std");

pub fn main() !void {
   const arr = [_]u8{1,2,3};
   const foo = &arr;

   std.debug.print("{}", .{arr[2]});
   std.debug.print("{}", .{foo[2]});
}

AFAIK these are the only three instances of this behavior. In all other cases if something asks for a pointer you have to explicitly provide it. Even when you pass an array to a function that accepts a slice, you will have to take the array's pointer explicitly.

The authoritative source of information is the language reference but checking it quickly, it doesn't seem to have a dedicated paragraph. Maybe there's some example that I missed though.
https://ziglang.org/documentation/0.8.0/

Upvotes: 4

Related Questions