Implicit pointer dereference on member access #671
Replies: 8 comments 13 replies
-
How can we access the member pointer itself? For example (UFCS): print: (dep: *dependency) = {
std::cout << "Print from a free function.\n";
}
x.dep.print(); |
Beta Was this translation helpful? Give feedback.
-
Would this compiler check you're asking for break the context free compiling?
Also I believe references are not going to be in cpp2 anyway, afaik they were mainly added for parameter passing, but cpp2 uses in, out, inout etc
On 11 September 2023 00:09:13 Roman Gilg ***@***.***> wrote:
Dependency injection is a wildly used pattern that I try to use whenever possible in C++ instead of globals. Another pattern is composition and I usually divide larger classes into smaller ones that are composited into each other. Both patterns allow duck typing in a sense that you can do a.b.c.f().
But in C++ this is not uniformly doable for dependencies that are reference types due to pointers having -> syntax and C++ references being problematic as members of a class.
Would it be doable and a good idea to allow in cppfront the same syntax for accessing the fields and methods of (dependencies as) pointers like these of (composited) value types? This would simplify the language and ease the usage of dependency injection.
Here a small cppfront code example of what I mean (see last line in main where dereferencing is necessary):
dependency : type = {
print: (this) = {
std::cout << "print from dependency\n";
}
}
composite : type = {
// Without int parameter doesn't compile for some reason...
operator=: (out this, _: int) = {
}
print: (this) = {
std::cout << "print from composite\n";
}
}
my_class : type = {
operator=: (out this, d: *dependency) = {
dep = d;
}
print: (this) = {
std::cout << "print from my_class\n";
}
public dep: *dependency;
public cmp: composite = (1);
}
main: () = {
d: dependency = ();
x: my_class = (d&);
x.print();
x.cmp.print();
x.dep*.print();
// Instead: x.dep.print()
}
I'm not sure how this should interact with UFCS. Maybe the compiler should check if there is a free function with the same name taking a pointer of the type as first argument and if yes, prefer the free function, or it should error out then because of ambiguity.
—
Reply to this email directly, view it on GitHub<#671>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AALUZQMCL2ZZXEPCBI63YZ3XZZCBPANCNFSM6AAAAAA4SPJJGU>.
You are receiving this because you are subscribed to this thread.Message ID: ***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
Rust has a feature like this where the smart pointers do auto-dereferencing. But it is implemented at a library level and for things like vector, string, smart pointers etc. Similar to how vectors overload the operator |
Beta Was this translation helpful? Give feedback.
-
Thanks, this is a good question. In general, Cpp2 goes to "explicit is better than implicit." A lot of Cpp2's simplifications come from removing "implicit invisible magic," such as a magic invisible "this" parameter and magic invisible one-default-fits-all compiler-generated SMFs. This question touches directly on an example I've used as a poster-child motivating example, namely: It's vital to be able to say clearly which object you're talking about. Therefore, in a language with pointers (and aren't they all these days?), it's vital to be able to distinguish the pointer and the pointee. For example, let's say we have a type
With explicit deref, there's a simple and clear distinction between
|
Beta Was this translation helpful? Give feedback.
-
I think I should motivate automatic pointer dereferencing some more. In the past C++ code was often written with an OO focus. It was "C + classes". When I look at the legacy code of projects I worked on, in open source and industry, this is hardly not to notice. The result was huge classes with deep inheritance hierarchies and a lot of boiler plate code. The typical example for me is Qt in this regard. In contrast I - and from what I see online many other C++ developers embracing modern programming techniques - favor small structs together with functional and generic programming techniques. For example this struct from one of my own projects contains the topology data of a window that means data describing the window in context of the overall space structure. It does not do anything else, its purpose is clear, it is composited into a window like this. Now assume I want to create a library that is consumed by other projects. And assume I provide some struct that comes with few public data fields like the above struct. Is it really important for the consumer if these fields reference other values or are values themselves? I would say that this is an implementation detail. The consumer only wants to access the data, not know about the memory structure behind that. In the example with the topology data of window why should it make a difference how a consumer access window topology data like we do in this test? These elements should be accessed through The bottom line is that it shouldn't matter if this data is referenced or not. External consumers of my types should not have to care about the memory model. The solution to this is often to have getters and access all data through these. But this is boiler plate and makes classes fat again. The best data structure for me is small having few public fields. And all transformations to this data structure go through generic functions. Also at the end a somewhat weaker argument, but let's take a look at other programming languages. I can access data in Rust like this |
Beta Was this translation helpful? Give feedback.
-
Correct me if I'm wrong, but it sounds like this is really asking for (all) smart pointers to be treated as smart references? |
Beta Was this translation helpful? Give feedback.
-
You could go the other way around and write
|
Beta Was this translation helpful? Give feedback.
-
As another modern language example; in Go implicit pointer dereferencing is also a thing: https://go.dev/tour/moretypes/4
|
Beta Was this translation helpful? Give feedback.
-
Dependency injection is a widely used pattern that I try to use whenever possible in C++ instead of globals. Another pattern is composition and I usually divide larger classes into smaller ones that are composited into each other. Both patterns allow duck typing in a sense that you can do something like
a.b.c.f()
.But in C++ this is not uniformly doable for dependencies that are reference types due to pointers having
->
syntax and C++ references being problematic as members of a class.Would it be doable and a good idea to allow in cppfront the same syntax for accessing the fields and methods in a (dependency as) pointer like these of a (composited) value type? This would simplify the language and ease the usage of dependency injection.
Here a small cppfront code example of what I mean (see last line in main where dereferencing is necessary):
I'm not sure how this should interact with UFCS. Maybe the compiler should check if there is a free function with the same name taking a pointer of the type as first argument and if yes, prefer the free function, or it should error out then because of ambiguity.
Beta Was this translation helpful? Give feedback.
All reactions