Aliases for any names (variables, functions etc.)

234 views
Skip to first unread message

Yuriy Smirnov

unread,
May 18, 2015, 12:54:58 PM5/18/15
to std-pr...@isocpp.org
Hello! I want to create aliases for any names in program (not only types and templates). I propose to use "using" keyword for this. For example:

struct Base
{
 
int x;
 
int arr[2];
 
void foo(int,char){}
};
struct Derived : Base
{
 
void foo(float){}
  std
::pair<char,char> p;

  using y = x; // add alias for 'x' member
 
using a1 = a[1];
 
using f1 = foo(int,char);
 
using g2 = foo(float);
 
using p2 = p.second;
};
Base b;
Derived d;

d
.x = 10; // ok
d
.y = 20; // ok, the same as 'd.x =20'
b
.y = 30; // error, 'y' defined only for 'Derived'
d
.f1(100,'a'); // call foo(int,char)
d
.f2(3.14);// call foo(float)
d
.p2 ='q'; // d.p.second ='q'

In large programs with hundreds and thousands of classes in inheritance hierarchy, it is maybe useful for clarification of semantic of some variables and methods. Using of alias names will narrow the search to those names for the project. For example, field 'name' in root class could be aliased as 'name_car', 'name_aircraft', 'name_ship' etc.


Nevin Liber

unread,
May 18, 2015, 1:27:49 PM5/18/15
to std-pr...@isocpp.org
On 18 May 2015 at 11:54, Yuriy Smirnov <neoprog...@gmail.com> wrote:
In large programs with hundreds and thousands of classes in inheritance hierarchy, it is maybe useful for clarification of semantic of some variables and methods. Using of alias names will narrow the search to those names for the project. For example, field 'name' in root class could be aliased as 'name_car', 'name_aircraft', 'name_ship' etc.

Surely that would exasperate the problem, as now you have to search for two names instead of just one.
--
 Nevin ":-)" Liber  <mailto:ne...@eviloverlord.com(847) 691-1404

Nicol Bolas

unread,
May 18, 2015, 1:44:42 PM5/18/15
to std-pr...@isocpp.org
On Monday, May 18, 2015 at 12:54:58 PM UTC-4, Yuriy Smirnov wrote:
In large programs with hundreds and thousands of classes in inheritance hierarchy, it is maybe useful for clarification of semantic of some variables and methods. Using of alias names will narrow the search to those names for the project. For example, field 'name' in root class could be aliased as 'name_car', 'name_aircraft', 'name_ship' etc.

I agree with Nevin on this; I can't see how that would in any way help. Indeed, your example suggests a very odd way of thinking about these sorts of things.

If a base class has a field simply called `name`, then presumably that refers name refers to the object itself. If I have a class derived from whatever type this is, and I call that class "Car", then `name` would refer to the name of the "Car". So there's no confusion over what the name refers to; renaming it to `name_car` adds only needless verbosity.

It also adds confusion, since now it's much harder to track down what actual variable is being used. You can't just search for a particular word; now you have to search for multiple words.

Furthermore, derived classes shouldn't be renaming things from base classes. The name of a variable provides its meaning; to change the name is to change its meaning. `name` is a "name" because that's what the word means. Derived classes should change the contents of such variables, not their meaning. `name` should always be the object's name, regardless of how derived it is. Otherwise, you're just creating lots of confusion.

We allow type and template aliases because of verbosity; the names of these things can be exceptionally long. Types can be nested within lots of namespaces and/or other types. Templates, particularly with default parameters, can be gigantic. So we have a way to take a long name and assign it to a shorter one.

By contrast, variable names are usually only as long as the textual name itself. So if a name is too long, just shorten it.

Richard Smith

unread,
May 18, 2015, 4:37:32 PM5/18/15
to std-pr...@isocpp.org
On Mon, May 18, 2015 at 9:54 AM, Yuriy Smirnov <neoprog...@gmail.com> wrote:
Hello! I want to create aliases for any names in program (not only types and templates). I propose to use "using" keyword for this. For example:

struct Base
{
 
int x;
 
int arr[2];
 
void foo(int,char){}
};
struct Derived : Base
{
 
void foo(float){}
  std
::pair<char,char> p;

  using y = x; // add alias for 'x' member
 
using a1 = a[1];

How is this supposed to be parsed? We don't know the type of 'this' here. Consider:

struct X { int n; };
struct Y { template<int> int n(int); };
struct A {
  X operator[](int);
  Y operator[](int) const;
};
A a;
// For non-const this, (this->A::a[0].X::n < 0) > (0)
// For const this, this->A::a[0].Y::n<0>(0)
using b = a[0].n<0>(0);


 
using f1 = foo(int,char);
 
using g2 = foo(float);
 
using p2 = p.second;
};
Base b;
Derived d;

d
.x = 10; // ok
d
.y = 20; // ok, the same as 'd.x =20'
b
.y = 30; // error, 'y' defined only for 'Derived'
d
.f1(100,'a'); // call foo(int,char)
d
.f2(3.14);// call foo(float)
d
.p2 ='q'; // d.p.second ='q'

In large programs with hundreds and thousands of classes in inheritance hierarchy, it is maybe useful for clarification of semantic of some variables and methods. Using of alias names will narrow the search to those names for the project. For example, field 'name' in root class could be aliased as 'name_car', 'name_aircraft', 'name_ship' etc.


--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

Douglas Boffey

unread,
May 19, 2015, 4:40:02 AM5/19/15
to std-pr...@isocpp.org


On Monday, 18 May 2015 21:37:32 UTC+1, Richard Smith wrote:
On Mon, May 18, 2015 at 9:54 AM, Yuriy Smirnov <neoprog...@gmail.com> wrote:
Hello! I want to create aliases for any names in program (not only types and templates). I propose to use "using" keyword for this. For example:

struct Base
{
 
int x;
 
int arr[2];
 
void foo(int,char){}
};
struct Derived : Base
{
 
void foo(float){}
  std
::pair<char,char> p;

  using y = x; // add alias for 'x' member
 
using a1 = a[1];

How is this supposed to be parsed? We don't know the type of 'this' here. Consider:

I think the ‘using a1 = a[1];’ should have been ‘using a1 = arr[1];’ (referring to Base::arr).

Matthew Woehlke

unread,
May 19, 2015, 10:48:58 AM5/19/15
to std-pr...@isocpp.org
On 2015-05-18 12:54, Yuriy Smirnov wrote:
> Hello! I want to create aliases for any names in program (not only types
> and templates). I propose to use "using" keyword for this. For example:

[example snipped]

This sounds a lot like the inline expressions proposal.

I'm inclined to agree with others; renaming for the sake of renaming
does not "feel" like good coding.

Inline expressions are more powerful and focused on more important use
cases, such as modifying the cv-qualifiers on a member variable
depending on the access level.

> In large programs with hundreds and thousands of classes in inheritance
> hierarchy, it is maybe useful for clarification of semantic of some
> variables and methods.

Heh. You know, what we *really* need is better search support from
IDE's. The ability to find all uses of a particular type or member, for
instance. If we had that, it would not be so hard to extend it to
finding all instances of a base member used in the context where the
owning object is a particular subclass.

--
Matthew

Richard Smith

unread,
May 19, 2015, 3:52:45 PM5/19/15
to std-pr...@isocpp.org
I think you have missed the point of my question. 

Yuriy Smirnov

unread,
May 20, 2015, 3:48:38 PM5/20/15
to std-pr...@isocpp.org
As well as without aliases. If some alias expression can not be interpreted explicitly, this is compile error. In fact, I want to have replacement for "#define" preprocessor directive, follows the rules of namespaces. I.e. "#define" only for scope of some class, function, namespace etc. I have seen the use of "#define" inside classes this way in real code, it's not nice and can cause errors, since "#defines" are are global and can affect the code outside class/namespace.

Richard Smith

unread,
May 20, 2015, 5:31:30 PM5/20/15
to std-pr...@isocpp.org
On Wed, May 20, 2015 at 12:48 PM, Yuriy Smirnov <neoprog...@gmail.com> wrote:
As well as without aliases.

Without aliases, every expression that refers to 'this' or a non-static data member specifies a type for 'this'. You don't have a type for 'this' in your alias, and it can parse in *completely* different ways depending on the constness of 'this'. You need to specify how that works, or you just have an idea rather than a proposal.

(If you can find a good solution to this problem, I think this is a very valuable feature; in fact, I considered proposing this feature -- with the semantics you describe -- several months ago but held back because of this very problem.)

You should probably also consider cases where it's desirable for the alias to behave differently based on the value category of the object:

struct X { X(); std::unique_ptr<int> u; using v = u; };
auto a = X().u; // ok, X().u is an xvalue per 5.2.5/4.2
auto b = X().v; // is this ok? what's the value category of X().v?
 
If the answer is "stash away the tokens and parse them when the alias is used", then you will get over-my-dead-body opposition from various committee members, myself included. If you can find some way to actually allow the alias to be parsed, and still do something reasonable in the cases I've described, your proposal is likely to fare a lot better.

robi...@gmail.com

unread,
Jun 6, 2015, 3:59:45 AM6/6/15
to std-pr...@isocpp.org
I've wanted aliasing for a long time in C++ as it elegantly solves (1) the cases where you need to implement identical functions with distinct names (without the silliness of forwarding every call), and (2) it nicely allows incremental data member renames without requiring a large search and replace at once.

(1) In our codebase, class functions are PascalCase'd (IsEmpty, Resize, GetSize, GetData...), but it's also common to want to compatibility with STL containers and genericity in template algorithms. This leaves us declaring methods (empty, resize, size, data...) that are just dumb forwarders to the real call. IsEmpty and empty are not different functions though - they are really the same function just with different names, and repeating the return value and parameter names is wasted time and space when you could just say using empty = IsEmpty.

(2) When you refactor a codebase, it's not feasible to search and replace every usage of a struct field all at once, especially when multiple code branches are all actively making changes, and merge conflicts are real. I'd need persuasion for something complex like using a1 = a[1] or using p2 = p.second, but for simple aliasing at the same level, I definitely see the need (mind you, I'm less concerned about language purity and potential abuse {because really, anything can be abused, including 'goto') and more concerned with practicality). A #define macro cannot accomplish this cleanly because it cuts across every instance of a field/function of that name, when what you really need is a scoped alias.

Were you by chance inspired by D's 'alias'? http://dlang.org/declaration.html#AliasDeclaration

Sean Middleditch

unread,
Jun 7, 2015, 1:38:11 AM6/7/15
to std-pr...@isocpp.org, robi...@gmail.com
On Saturday, June 6, 2015 at 12:59:45 AM UTC-7, robi...@gmail.com wrote:
(1) In our codebase, class functions are PascalCase'd (IsEmpty, Resize, GetSize, GetData...), but it's also common to want to compatibility with STL containers and genericity in template algorithms. This leaves us declaring methods (empty, resize, size, data...) that are just dumb forwarders to the real call. IsEmpty and empty are not different functions though

An important facet of this is that you end up adding considerable overhead in debug builds unless you know the magic implementation-specific incantations to turn off all kinds of (otherwise beneficial) debug and security checks. Even then, unless you turn on inlining (and trust your implementation to not harm debuggability too much), even the "purest" of function calls can add up. And in modern C++, so many basic boolean conversions or pointer dereferences are secretly function calls.

In games, this is the "debug a slideshow" problem. It's fixable, but only if you (a) avoid much of C++'s utility and (b) have knowledge of implementation-specific configuration and hacks. It's telling how you can get a rather substantial speed boost by reimplementing std::vector and doing _nothing_ other than using raw pointers for iterators and refusing to let any "inline" member function call another inline member function, even if that means repeating a lot of fussy code.

A function alias would, I'd suppose, have zero runtime overhead (even in zero-optimization debug builds with implementation "value adds" like stack checks). That's worth something to people who care about run-time debug speed, compilation speed, debug binary size, symbol bloat, link times, etc.

Jim Porter

unread,
Jun 7, 2015, 2:01:03 PM6/7/15
to std-pr...@isocpp.org
On 5/18/2015 11:54 AM, Yuriy Smirnov wrote:
> In large programs with hundreds and thousands of classes in inheritance
> hierarchy, it is maybe useful for clarification of semantic of some
> variables and methods. Using of alias names will narrow the search to
> those names for the project. For example, field 'name' in root class
> could be aliased as 'name_car', 'name_aircraft', 'name_ship' etc.

I've wanted a feature like this too, but for different reasons. I prefer
to use descriptive names for any non-local identifiers (functions,
classes, members, global variables), but sometimes these can be quite
verbose. When I'm inside a function and want to use
a function like `make_thing_with_a_very_long_name` several times, it
would be useful to be able to alias it to something shorter.

This is what I already do for namespaces. I only say `using namespace
foo` inside of functions where I use that namespace a bunch*. Otherwise,
I think it's better to use the fully-qualified name, as that makes it
clearer.

- Jim

* Well, I also say `using namespace std` for ADL hacks for std::swap and
such...

Nevin Liber

unread,
Jun 7, 2015, 2:17:18 PM6/7/15
to std-pr...@isocpp.org
On 7 June 2015 at 13:00, Jim Porter <jvp...@g.rit.edu> wrote:
When I'm inside a function and want to use
a function like `make_thing_with_a_very_long_name` several times, it would be useful to be able to alias it to something shorter.

Why not use a lambda for this?

Sean Middleditch

unread,
Jun 7, 2015, 2:26:07 PM6/7/15
to std-pr...@isocpp.org


On Jun 7, 2015 11:17 AM, "Nevin Liber" <ne...@eviloverlord.com> wrote:
>
> On 7 June 2015 at 13:00, Jim Porter <jvp...@g.rit.edu> wrote:
>>
>> When I'm inside a function and want to use
>> a function like `make_thing_with_a_very_long_name` several times, it would be useful to be able to alias it to something shorter.
>
>
> Why not use a lambda for this?

Can you have variadic lambdas now? Otherwise, you have to painstakingly respecify much of the signature to forward.

Also, they'd  still be more heavyweight machinery than necessary for an alias.

Also also, how would lambdas here interact with refactoring tool support? Tools could see through aliases easily, but seeing through forwarding wrappers has so far been problematic (there's a lack of semantic information that forwarding is the function's intent or purpose).

Also^3, why not just use a macro? *ducks*


> --
>  Nevin ":-)" Liber  <mailto:ne...@eviloverlord.com(847) 691-1404
>

> --
>
> ---
> You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/MkopUDw0JhU/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to std-proposal...@isocpp.org.

martin...@gmx.de

unread,
Jun 30, 2015, 5:04:03 PM6/30/15
to std-pr...@isocpp.org
How about the following:

class Foo {
   
int a;
public:
   
using(const int) b = a;
   
// etc...
};



Basically the syntax is

using(type) name = expr;



This sounds quite interesting, given that with the upcoming concepts, you might have to implement the method with a given name. I could imagine that you could declare public aliases even outside the class so that the class can match a concept. Consider a c-class like this:

struct Bar {
   
int x, y, z;
};

int bar_equals(Bar*, Bar*);

using(bool Bar::*bar) operator==(const Bar& other) = bar_equals(bar, &other);



This way you can add the operator== even if the original definition didn't mention it at all. The keyword is reused, and you can now compare two Bars with bar1 == bar2;
I can also imagine a syntax to undeclare a name in a specific scope, meaning that that name isn't visible after the undeclaration:

void func(FILE* hnd) {
    raii_closer endofscope
{hnd};
   
using raii_closer=; // "Undeclare raii_closer"
}


Reply all
Reply to author
Forward
0 new messages