Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add std.meta #1662

Merged
merged 20 commits into from Oct 19, 2018

Conversation

Projects
None yet
2 participants
@tgschultz
Copy link
Contributor

tgschultz commented Oct 18, 2018

Added the beginning of std.meta from the branch started by @Hejsil and @andrewrk, which is intended to replace a lot of built-in functions over time, as well as std.meta.trait which is a collection of shortcuts to simple type introspections like determining if a type has an fn definition with a specific name.

tgschultz added some commits Jun 6, 2018

Merge pull request #3 from ziglang/master
Sync with upstream master
Fix old syntax in rand
Ziggurat somehow did not get updated to latest syntax
Fix broken float casts
f32 float casts somehow not updated to latest syntax
Merge pull request #6 from ziglang/master
Sync with upstream
/// Otherwise it returns the type as-is.
pub fn UnwrapContainer(comptime T: type) type
{
comptime

This comment has been minimized.

Copy link
@Hejsil

Hejsil Oct 18, 2018

Member

Pretty sure functions returning type are always evaluated at comptime

This comment has been minimized.

Copy link
@tgschultz

tgschultz Oct 18, 2018

Author Contributor

Chalk it up to paranoia from seeing too many bugs due to something being evaluated as runtime for non-obvious reasons.



///Returns the active tag of a tagged union
pub fn activeTag(u: var) @TagType(UnwrapContainer(@typeOf(u)))

This comment has been minimized.

Copy link
@Hejsil

Hejsil Oct 18, 2018

Member

I don't think this function should take pointers and deref it. It should just take the value, and the user is responsible for the deref.

This comment has been minimized.

Copy link
@tgschultz

tgschultz Oct 18, 2018

Author Contributor

That makes sense, given that the compiler should ensure that no copies of large structs occur.

}
///Given a pointer to a single item, returns a slice of the underlying bytes, preserving the
/// pointer's const-ness.
pub fn bytes(ptr: var) BytesReturnType(@typeOf(ptr))

This comment has been minimized.

Copy link
@Hejsil

Hejsil Oct 18, 2018

Member

Maybe this should be in std.mem instead. We should also probably return an array pointer instead of a slice, as we know the size of the data we are returning. I have a simular implementation of this here. I think we could have toBytes and asBytes where asBytes return a slice with the correct attributes, and toBytes just returns a copy of the data as bytes.

This comment has been minimized.

Copy link
@Hejsil

Hejsil Oct 18, 2018

Member

And maybe we should also have a bytesToValue and bytesAsValue that takes an array/array pointer respectively and returns a packed value/pointer to packed value.

This comment has been minimized.

Copy link
@tgschultz

tgschultz Oct 18, 2018

Author Contributor

Makes sense to me.

Show resolved Hide resolved std/meta/index.zig Outdated
pub fn containerEql(container_a: var, container_b: var) bool
{
const T = UnwrapContainer(@typeOf(container_a));
debug.assert(UnwrapContainer(@typeOf(container_b)) == T);

This comment has been minimized.

Copy link
@Hejsil

Hejsil Oct 18, 2018

Member

Again, I don't think we should take pointers. Let the function take values, and let the user deref.


///Compares two structs or (tagged) unions for equality on a field level
/// so that padding bytes are not relevant.
pub fn containerEql(container_a: var, container_b: var) bool

This comment has been minimized.

Copy link
@Hejsil

Hejsil Oct 18, 2018

Member

Why only containers? We could do a generic eql that supports all types.

This comment has been minimized.

Copy link
@tgschultz

tgschultz Oct 18, 2018

Author Contributor

Actually that was the original implementation, but it seemed to me that it might be a bad idea to have such a broad implementation. For instance, the only reasonable way to compare two untagged unions is to use mem.eql, but that comparison could be wrong. If the user is used to just calling meta.eql on everything, including untagged unions, that comparison will sometimes fail when it would be expected to succeed.

This comment has been minimized.

Copy link
@Hejsil

Hejsil Oct 18, 2018

Member

Makes sense, but we could just make untagged unions call @compileError. Most types compare equal just fine.

Show resolved Hide resolved std/meta/trait.zig Outdated
};

debug.assert(hasField("value")(TestStruct));
debug.assert(hasField("value")(*TestStruct));

This comment has been minimized.

Copy link
@Hejsil

Hejsil Oct 18, 2018

Member

I know, that . can access through pointers, but Idk if we really wanna "lie" to the user because of this. The pointer does not have any fields. . just does a little magic.

This comment has been minimized.

Copy link
@tgschultz

tgschultz Oct 18, 2018

Author Contributor

In generic code, the user probably doesn't care if they were passed a pointer or not, as long as they can call/access some needed function/field.

This comment has been minimized.

Copy link
@tgschultz

tgschultz Oct 18, 2018

Author Contributor

Actually, I think you're right. Instead we'll have the user call UnwrapContainer(T) --I am all ears for naming suggestions-- themselves if that's the behavior they want.

if(is(builtin.TypeId.Pointer)(T))
{
const info = @typeInfo(T);
return info.Pointer.size != builtin.TypeInfo.Pointer.Size.One;

This comment has been minimized.

Copy link
@Hejsil

Hejsil Oct 18, 2018

Member

We can index array pointers (*[N]T)

@Hejsil
Copy link
Member

Hejsil left a comment

Looks pretty good now (only two small things). The trait function will be really useful if we ever get var<func> :)

const TypeId = builtin.TypeId;
const TypeInfo = builtin.TypeInfo;

pub fn UnwrapContainer(comptime T: type) type

This comment has been minimized.

Copy link
@Hejsil

Hejsil Oct 18, 2018

Member

Now, we probably don't need this anymore :)

This comment has been minimized.

Copy link
@tgschultz

tgschultz Oct 18, 2018

Author Contributor

Maybe. I think it might still be useful for generic code that doesn't care if it is passed a pointer or not as long as it can call/access var.whatever. I used to do this a lot before #733, so it might not be as useful an idea now. I'll think on it for a bit.


///Compares two structs or (tagged) unions for equality on a field level
/// so that padding bytes are not relevant.
pub fn containerEql(container_a: var, container_b: @typeOf(container_a)) bool

This comment has been minimized.

Copy link
@Hejsil

Hejsil Oct 18, 2018

Member

I still think we probably just want a fully generic equal, if we're gonna have this one


//This is the only reasonable way to handle an untagged union,
// but it will report a false negative in many circumstances.
return std.mem.eql(u8, mem.asBytes(&a), mem.asBytes(&b));

This comment has been minimized.

Copy link
@Hejsil

Hejsil Oct 19, 2018

Member

It's probably better if this is a compiler error, to avoid the bugs, where padding bytes are different

@Hejsil

This comment has been minimized.

Copy link
Member

Hejsil commented Oct 19, 2018

Other than some of the code not following the style of std, this PR LGTM

std/mem.zig Outdated
pub fn bytesAsValue(comptime T: type, bytes: var) BytesAsValueReturnType(T, @typeOf(bytes))
{
return @ptrCast(BytesAsValueReturnType(T, @typeOf(bytes)),
@alignCast(comptime meta.alignment(T), bytes));

This comment has been minimized.

Copy link
@Hejsil

Hejsil Oct 19, 2018

Member

This cast failes on macos, because the bytes we pass in are not aligned with our type. Maybe we should return *align(1) T?

This comment has been minimized.

Copy link
@Hejsil

Hejsil Oct 19, 2018

Member

And maybe asBytes should return *align(comptime alignment(@typeOf(ptr))) [@sizeOf(@typeOf(ptr))]

Show resolved Hide resolved std/mem.zig

tgschultz added some commits Oct 19, 2018

Altered asBytes and bytesAsValue to have more appropriate alignment. …
…Removed to* variations as they are trivially replicated with 2 characters at the as* callsites.
Was convinced to re-add to* variations for convenience & saftey. Made…
… bytesAsValue alignment match alignment of byte buffer.

I'm not 100% sure that's actually a good idea though.

@Hejsil Hejsil merged commit 2a3fdd5 into ziglang:master Oct 19, 2018

2 checks passed

continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details

tgschultz added a commit to tgschultz/zig that referenced this pull request Oct 20, 2018

@tgschultz tgschultz deleted the tgschultz:std-meta branch Oct 20, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.