We can increase type safety in C++ by adding a single keyword. The current proposal uses the keyword "only".
Example 1:
only int x= 4;
x= 5; // Ok
x= 5.0; // Error
x= 5U // Error
Example 2:
int i= 5;
only unsigned x= 4U;
x= 5; // Error
x= 5LU; // Error
x= i; // Error
Example 3:
only float f= 4.0F;
f= 4; // Error
f= 5.0; // Error
f= 4.0F; // OK
// It accepts any built in type
void somefunc(const int &x);
// It accepts only an int and a const int object
void somefunc(only const int &x);
It is simple like that, and the concept is backwards compatible.
What do you think?
I think I don't have a clear understanding of what problem this solves.
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Up to here you can use "const" keyword to let the compiler know that
value is constant or use compile-time constant expression which is
even better.
> // It accepts any built in type
> void somefunc(const int &x);
>
> // It accepts only an int and a const int object
> void somefunc(only const int &x);
>
Both functions in your example accepts constant reference to object of
type "int" and I don't see what difference the "only" keyword makes.
So what is the point?
Type safety, more specifically, avoiding implicit type conversions.
The point of the proposal is that in the first case:
// It accepts any built in type
void somefunc(const int &x);
We can do:
somefunc(45.76);
while in the second case:
// It accepts only an int and a const int object
void somefunc(only const int &x);
somefunc(45.76);
would be a compiler error.
That's not a problem. That's a solution. What's the problem with those?
As I recall someone proposed a similar class template a while back.
But even if nobody did, I do that now, so, it's done:
template< typename T >
class Only
{
private:
T myValue;
template< typename U > Only( U v ); // No constr. from other types.
public:
// STATIC_ASSERT( that T is built-in type or something like that )
Only( T v ): myValue( v ) {}
T value() const { return myValue; }
operator T () const { return value(); }
};
Disclaimer: above code is off-the-cuff, not fondled by any dirty compiler.
Hm, thinking of it I have actually proposed something very similar earlier, many
years ago, namely, for the purpose of ensuring 'bool' conditional expressions in
novice code.
However, that proposal was shot down by (1) others' ideas about how unsuitable
this was for novices, and (2) actually trying it, which showed that the
standard's formal UB for redefining a keyword when using standard library
headers, is not just formal UB but, with at least one compiler, very real...
Cheers,
- Alf
--
Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
No ads, and there is some C++ stuff! :-) Just going there is good. Linking
to it is even better! Thanks in advance!
What is the problem with that code? Implicit conversion in that case
is acceptable. In C++ and many other languages this is done to take
advantages of type hierarchies and I don't see any problems with that.
The only problem you may face is unfavorable implicit conversions of
high-level classes, but C++ has "explicit" keyword to prevent that.
--
VH
template<class Value_type>
class only
{
Value_type m_value;
template<class U> only(U);
public:
typedef Value_type value_type;
typedef Value_type& reference;
only(value_type value)
: m_value( value ) { }
value_type value() const {
return m_value;
}
};
void example1() {
only<int> x = 4;
x = 5; /* OK */
// x = 5.0; /* Error */
// x = 5U; /* Error */
}
void example2() {
int i = 5;
only<unsigned> x = 4U;
// x = 5; /* Error */
// x = 5UL; /* Error */
// x = i; /* Error */
}
void example3() {
only<float> f = 4.0F;
// f = 4; /* Error */
// f = 5.0; /* Error */
f = 4.0F; /* OK */
}
> // It accepts any built in type
> void somefunc(const int &x);
No, it doesn't. It accepts exactly the set of builtin types with
implicit conversions to int.
> // It accepts only an int and a const int object
> void somefunc(only const int &x);
Partial specialization of "only" for reference types is left as an exercise.
> What do you think?
I think the C++ static type system is already absurdly powerful. I'd
rather see compilers optimized for template metaprogramming, than see
the language changed to make existing features more approachable.
I proposed it in c.l.c.moderated, as a response to Andrei Alexandrescu.
Dave Abrahams was also on the thread. I'm too lazy to look for the
thread just this moment.
> But even if nobody did, I do that now, so, it's done:
>
> template< typename T >
> class Only
> {
> private:
> T myValue;
>
> template< typename U > Only( U v ); // No constr. from other
> types.
>
> public:
> // STATIC_ASSERT( that T is built-in type or something like that )
> Only( T v ): myValue( v ) {}
>
> T value() const { return myValue; }
> operator T () const { return value(); }
> };
>
> Disclaimer: above code is off-the-cuff, not fondled by any dirty compiler.
>
> Hm, thinking of it I have actually proposed something very similar
> earlier, many years ago, namely, for the purpose of ensuring 'bool'
> conditional expressions in novice code.
>
> However, that proposal was shot down by (1) others' ideas about how
> unsuitable this was for novices, and (2) actually trying it, which
> showed that the standard's formal UB for redefining a keyword when using
> standard library headers, is not just formal UB but, with at least one
> compiler, very real...
I don't recall (1) being suggested, and I'm not sure what you mean by
(2). What keyword is being "redefined?"
huh
> and I'm not sure what you mean by
> (2). What keyword is being "redefined?"
if, while
Sorry, I misunderstood. When you say you "proposed something very
similar," I guess you mean adding a keyword, rather than using a template.
Actually, he wouldn't need to add a keyword. "explicit" could be
re-used instead of adding "only".
No, I meant a template.
It was in the "Correct C++ Tutorial" (only tutorial referenced by the FAQ,
available at URL below).
As I recall, due to the responses I eventually I rewrote that section/chapter
removing the point list of ways to deal with that language rule botch-up,
because if any were mentioned then also the restrict-the-language approach would
have to be mentioned. But I'm not sure. May be there still.
Cheers,
- Alf
More cases:
only double d1 = 1F; // That would be an error. Type mismatch (float assigned to double).
only double d2 = 1; // That would be an error. Type mismatch (int assigned to double).
d1 = 1F; // That would be an error. Type mismatch (float assigned to double).
d2 = 1; // That would be an error. Type mismatch (int assigned to double).
short s = 1; // That would be correct, since the keyword "only" is missing.
In the case of
only short s= 1;
it could be an error (type mismatch), if a postfix for short constants was provided, for example H/h.
short s= 1H; could work. And (UH/uh for unsigned short constants).
only int i = s; // That would be an error. Type mismatch (short assigned to int).
i = s; // That would be an error. Type mismatch (short assigned to int).
Another use of "only":
#include <iostream>
void somefunc(only int)
{
std::cout<< "somefunc(int) was called\n";
}
void somefunc(only double)
{
std::cout<< "somefunc(double) was called\n";
}
int main(void)
{
// OK, int is passed
somefunc(4);
// Error
somefunc(4U);
// OK, double is passed
somefunc(4.0);
// Error
somefunc(4.0F);
}
http://www.cpp-software.net/documents/cpp_only_proposal.html
So please base your answers to that document.
I am yet to see the actual *problem* with any of those cases. Is your
suggestion just for the sake of changing the language, making an impact,
so to speak?
If you have encountered a *real-world* problem that cannot be solved
without adding your new mechanism for preventing implicit conversions
and promotions, could you please state it?
I agree with Viktor. There are a lot of real-world problems where
implicit conversions of type hierarchies are extremely helpful. I
don't have a clue why you should deny them. It would be nice to see a
real-world problem where you need it.
Also, what do you think about denying explicit casting?
http://en.wikibooks.org/wiki/C%2B%2B_Programming/Type_Casting
What you say is a correct approach. I have to note here, that the proposal is a work in progress, and it
doesn't explain what happens with classes, class hierarchies, etc, yet.
The next thing to be added, is how the keyword would work in constructors.
Well, given the proposal as it currently is, an example of real world type safety problem, is having a
function returning a double:
only double somefunc()
{
double value= 1.0;
// Perform some operations
return value;
}
int main()
{
int x= somefunc(); // The compiler catches the error
}
Ioannis,
I don't see any problem with that code at all. It might be a desired
behavior.
Assuming that "only double" keyword disables any kind of implicit
casting, I don't know why would someone need that, but Alf's solution
sounds better anyway. No need for extra keyword, just wrap that POD
type with a smart template and you are there.
Also, there is "auto" keyword in upcoming C++ standard. It solves
another problem, however, works out this case:
auto x = somefunc();
Consider the following completely type-safe code:
#include <iostream>
only double somefunc()
{
only double value= 1.0;
// Perform some operations
return value;
}
int main()
{
using namespace std;
only double result= somefunc();
only int x= static_cast<int>(result);
cout<< x<< endl;
}
Also, an interesting thing to note, is that we can make the code backwards compatible (that is, valid
C++98/03) by using a single
#define only
statement.
> Assuming that "only double" keyword disables any kind of implicit
> casting,
You mean, "implicit conversion".
> I don't know why would someone need that, but Alf's solution
> sounds better anyway. No need for extra keyword, just wrap that POD
> type with a smart template and you are there.
>
> Also, there is "auto" keyword in upcoming C++ standard. It solves
> another problem, however, works out this case:
>
> auto x = somefunc();
>
> Look at http://en.wikipedia.org/wiki/C%2B%2B0x
Yes, the proposal will be fully compatible with C++0x.
In particular, when we use the keyword auto without a type, the keyword "only" can not be used.
Examples:
only auto int x= 5; // OK
only auto x= 5; // Compiler error. "only" cannot be used with keyword auto without a type specified.
auto is a weak typing approach, while "only" keyword is a strong typing approach.
I think for both to work cleanly and for simplicity, they shouldn't be combined (although they could under
specific circumstances).
First, I think your comment is wrong:
"The new use of “auto” in upcoming C++0x, is a weak typing approach,
while "only" keyword is a strong typing approach."
The new "auto" is not less a strong typing approach than before (without
auto). You still can't change the type of a variable after declaration.
What "auto" does is called "type inference". It deduces the type of the
declared variable by the type of its initializer.
So an "only auto" variable would make sense:
only auto x = 5; // the type of x is "only int" now
x = 5.0; // can't assign double, because x is int.
Second, take a look at another proposal, for example the lambda proposal:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1968.pdf
Your proposal still lacks a motivation part (1.1 in the above) that
talks about **which problems you want to solve** with this solution, and
another part, which discusses why a simple library solution (some where
suggested) isn't good enough.
--
Thomas
It means that everyone who contributes to this proposal, and he wishes to take credit for his contribution,
his personal information will be included in the final text of the proposal, if the proposal becomes complete.
That's why, everyone who will contribute to this proposal, and wants to take a credit for his contribution,
can provide the following personal information, along with his proposal contributions:
Name [Middle Name] Last name, email address, [web site], [postal address].
The information inside the brackets is optional.
The contributions must be mainly syntax-based, and must comply with the design aims at the top of the page:
http://www.cpp-software.net/documents/cpp_only_proposal.html
You can post your contributions to the proposal, in this discussion thread.
Eric Sosman wrote:
>
> At a guess, you want an`only' keyword to mean that any
> initialization of or assignment to a variable must use an
> expression that is of the variable's exact type, without a
> conversion. Is that what you mean?
>
> One gap that seems evident is that you haven't specified
> what happens with type qualifiers. Do you intend to forbid
>
> only const char *p = "Hello, world!";
Yes, the proposal is under construction and doesn't cover all situations yet, however I think only
only const char * const p = "Hello, world!";
should compile, in this case (when we want to use the keyword "only").
> ... because the l.h.s. and r.h.s. disagree on const-ness?
> How about
>
> int i = 42;
> only void *q = &i;
"only" will not work with void pointers, in other words it would produce a compiler error.
This, because the aim of a void pointer is to be able to point to an object of any type, so it doesn't make
sense to use "only" with void pointers.
Which one?
Cross-posting & follow-up would be a good idea.
> Eric Sosman wrote:
>>
>> At a guess, you want an`only' keyword to mean that any
>> initialization of or assignment to a variable must use an
>> expression that is of the variable's exact type, without a
>> conversion. Is that what you mean?
>>
>> One gap that seems evident is that you haven't specified
>> what happens with type qualifiers. Do you intend to forbid
>>
>> only const char *p = "Hello, world!";
>
>
> Yes, the proposal is under construction and doesn't cover all situations
> yet, however I think only
>
> only const char * const p = "Hello, world!";
>
> should compile, in this case (when we want to use the keyword "only").
But it won't because string literals are of type < const char[] >.
>> ... because the l.h.s. and r.h.s. disagree on const-ness?
>> How about
>>
>> int i = 42;
>> only void *q = &i;
>
>
> "only" will not work with void pointers, in other words it would produce
> a compiler error.
>
> This, because the aim of a void pointer is to be able to point to an
> object of any type, so it doesn't make sense to use "only" with void
> pointers.
But a void pointer often is used pointing to raw memory, like in memory
allocators. Why do you want to propose a general type safety mechanism
and then forbid any useful usage?
--
Thomas
> First, I think your comment is wrong:
> "The new use of “auto†in upcoming C++0x, is a weak typing approach,
> while "only" keyword is a strong typing approach."
>
> The new "auto" is not less a strong typing approach than before (without
> auto). You still can't change the type of a variable after declaration.
> What "auto" does is called "type inference". It deduces the type of the
> declared variable by the type of its initializer.
I have updated http://www.cpp-software.net/documents/cpp_only_proposal.html
Take a look there for an explanation.
> Second, take a look at another proposal, for example the lambda proposal:
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1968.pdf
>
> Your proposal still lacks a motivation part (1.1 in the above) that
> talks about **which problems you want to solve** with this solution, and
> another part, which discusses why a simple library solution (some where
> suggested) isn't good enough.
A small example how increased type safety helps us:
only double somefunc()
{
double value= 1.0;
// Perform some operations
return value;
}
int main()
{
int x= somefunc(); // The compiler catches the error (type mismatch).
}
The proposal solves the problem of reduced type-safety, and aims to become a completely type-safe solution,
without changing the use of existing features.
For more info, and an example of a complete type safe program, check the proposal web page:
http://www.cpp-software.net/documents/cpp_only_proposal.html
The code:
const char * const p = "Hello, world!";
is valid C++98/03.
> But a void pointer often is used pointing to raw memory, like in memory
> allocators. Why do you want to propose a general type safety mechanism
> and then forbid any useful usage?
The void pointers were designed to point anywhere. Assigning a void pointer value to another type pointer
variable, always requires a cast under C+98/03, and keyword "only" will not interfere with that.
In other words, void pointers are designed to be unsafe (they point to an object of *any* type), so they
cannot be used together with keyword "only".
> A small example how increased type safety helps us:
>
>
> only double somefunc()
> {
> double value= 1.0;
>
> // Perform some operations
>
> return value;
> }
>
>
>
> int main()
> {
> int x= somefunc(); // The compiler catches the error (type mismatch).
> }
I don't know of a single compiler that would allow you to do this
without warning; I think they're required to. Most compilers have a
switch that allows you to make warnings an error. I think, perhaps,
that this is more what you want to illustrate:
int somefunc();
int main()
{
only double x = somefunc(); // error
}
I just don't see why that would help you. Furthermore, I'd very much
recommend against anything like this:
only int somefunc();
It's the caller's responsibility what to do with the information
returned by "somefunc", including to totally ignore it. Something like
this has a bit of a smell to it. Normally you have preconditions that
must be met before the function can be called, and postconditions that
must be supplied by the function. I've never heard of imposing
post-conditions that must be met by the client, yet that's what you seem
to be proposing by putting only in the declaration of the function.
In short, I wouldn't support such code and I see no useful purpose for
this language extension. If you really want this kind of behavior you
can get it from BOOST_STRONG_TYPEDEF.
The code:
double somefunc()
{
double value= 1.0;
// Perform some operations
return value;
}
int main()
{
int x= somefunc();
}
john@ubuntu:~/Projects/anjuta/cpp/src$ g++ -ansi -pedantic-errors -Wall main.cc -o foobar
main.cc: In function ‘int main()’:
main.cc:14: warning: unused variable ‘x’
john@ubuntu:~/Projects/anjuta/cpp/src$
So now you know one compiler that allows this without a warning.
john@ubuntu:~/Projects/anjuta/cpp/src$ g++ -v
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.3.2-1ubuntu12'
--with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++
--prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext
--enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3
--enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --enable-checking=release
--build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.3.2 (Ubuntu 4.3.2-1ubuntu12)
john@ubuntu:~/Projects/anjuta/cpp/src$
> I think, perhaps,
> that this is more what you want to illustrate:
>
> int somefunc();
> int main()
> {
> only double x = somefunc(); // error
> }
>
> I just don't see why that would help you. Furthermore, I'd very much
> recommend against anything like this:
>
> only int somefunc();
>
> It's the caller's responsibility what to do with the information
> returned by "somefunc", including to totally ignore it. Something like
> this has a bit of a smell to it.
If the programmer wants not having type safety on the returned type, he can define the function without the
keyword only, in the following style:
double somefunc()
{
only double value= 1.0;
// Perform some operations
return value;
}
int main()
{
int i= somefunc(); //OK
double d= somefunc(); //OK
only double od= somefunc(); // OK
}
So noone forces the programer to define the function returning "only double". In other words, the feature does
not get in the way of the programmer if he wishes not using it.
> Normally you have preconditions that
> must be met before the function can be called, and postconditions that
> must be supplied by the function. I've never heard of imposing
> post-conditions that must be met by the client, yet that's what you seem
> to be proposing by putting only in the declaration of the function.
If you do not want to use this type-safe ability of returning a value, you may not use it, while you may use
other abilities of "only", if you want.
Yes, aside from the fact that there is a new keyword...
I am still holding my breath for the rationale (and not consequences)
for this change. Any idea when you're going to come up with one?
> If you do not want to use this type-safe ability of returning a value,
> you may not use it, while you may use other abilities of "only", if you
> want.
I'm sorry, the argument that I don't have to use something just because
it's there is not sufficient for me to be convinced it should be added
to the language. I could say that about a lot of useless things.
Thanks anyway.
From http://www.cpp-software.net/documents/cpp_only_proposal.html:
"Why we need increased type safety: We need increased type safety, so as the compiler can help us avoid
mistakes and thus bugs in our code. Why a library solution isn't better: Because it would be too complex and
more limited, in comparison to the keyword based solution".
Don't you think that the code:
include <iostream>
void somefunc(only int)
{
std::cout<< "somefunc(int) was called\n";
}
void somefunc(only double)
{
std::cout<< "somefunc(double) was called\n";
}
int main()
{
// OK, int is passed
somefunc(4);
// Error
somefunc(4U);
// OK, double is passed
somefunc(4.0);
// Error
somefunc(4.0F);
}
is more type-safe than the code:
include <iostream>
void somefunc(int)
{
std::cout<< "somefunc(int) was called\n";
}
void somefunc(double)
{
std::cout<< "somefunc(double) was called\n";
}
int main()
{
// OK, int is passed
somefunc(4);
// Mistake, but compiles.
somefunc(4U);
// OK, double is passed
somefunc(4.0);
// Mistake, but compiles.
somefunc(4.0F);
}
> "Why we need increased type safety: We need increased type safety, so as
> the compiler can help us avoid mistakes and thus bugs in our code.
You have not made the case that your proposal adds type safety. If you
want types that don't support implicit conversions, they're easy enough
to write. It is not clear that the keyword buys you anything.
> Why a
> library solution isn't better: Because it would be too complex and more
> limited, in comparison to the keyword based solution".
Could you provide an example?
> is more type-safe than the code:
No. I can't reproduce your results. Not with g++ 3 anyway. Will check
4 when I get home.
>
>
> include <iostream>
>
>
> void somefunc(int)
> {
> std::cout<< "somefunc(int) was called\n";
> }
>
>
> void somefunc(double)
> {
> std::cout<< "somefunc(double) was called\n";
> }
>
>
> int main()
> {
> // Mistake, but compiles.
> somefunc(4U);
> }
Have you actually attempted to compile this code? Fails to resolve
ambiguity here. That's the only line that's mildly objectionable. I
don't consider the passing of a float into a double to be a type safety
issue.
class SomeClass
{
public:
SomeClass(int);
SomeClass(const SomeClass &);
};
int main()
{
SomeClass obj1= 5; // OK
SomeClass obj2= obj1; // OK
only SomeClass obj3= 5; // Compiler Error.
only SomeClass obj4= obj1; // OK
}
> Thomas J. Gritzan wrote:
>> Ioannis Vranos wrote:
>>
>>> Yes, the proposal is under construction and doesn't cover all
>>> situations yet, however I think only
>>>
>>> only const char * const p = "Hello, world!";
>>>
>>> should compile, in this case (when we want to use the keyword
>>> "only").
>>
>> But it won't because string literals are of type < const char[] >.
>
>
> The code:
>
> const char * const p = "Hello, world!";
>
> is valid C++98/03.
This is valid code because of an implicit conversion - which you want to
ban for some unclear reason.
Paavo
Thanks for reporting the mistake, I fixed the code.
I have to note something here: Everything that is relative to type-safety, and is effective in C++98/03,
continues to be effective under the "only" proposal.
The additional type safety via the new keyword "only", will be under the programmer's willingness to use it or
not.
The use of "only", does not prohibit the programmer to assign the value of a type to another type, it simply
requires him to specify his intentions explicitly.
The proposal is still a work in progress, and it doesn't cover pointers yet, however the assignment
only const char * const p = "Hello, world!";
will be valid.
The template I already posted on this thread gives exactly that
behavior. Consider this dead horse beaten anew:
template<class Value_type>
class only
{
Value_type m_value;
template<class U> only(U);
public:
typedef Value_type value_type;
only(value_type value)
: m_value( value ) { }
};
struct some_class
{
some_class( int ) { }
some_class( some_class const& ) { }
};
int main() {
some_class obj1 = 5; /* OK. */
some_class obj2 = obj1; /* OK. */
only<some_class> obj3 = 5; /* Compile-time error. */
only<some_class> obj4 = obj1; /* OK. */
}
Why do we need increased type safety?
> Why a
> library solution isn't better: Because it would be too complex and more
> limited, in comparison to the keyword based solution".
That's wrong. A library solution would be less complex, since the ~10
lines of code could be written once and distributed to all users, while
a core languages solution would have to be implemented in _all_ C++
compilers.
It's also less limited but more flexible, since we can easily adjust the
library solution if the situation changes or we find that the current
semantics are wrong in specific cases.
You won't convince anybody of your proposal by saying "we need it,
because we need it!"
--
Thomas
Less programming mistakes.
You keep repeating this, as if the more you say it, the more it would
make sense. But it doesn't. "Increased type safety" is meaningless
without the problem for which it's beneficial. I say the type safety at
the levels we already have is enough for any task out there. You seem
to say that it isn't. Please give the example where the "increase type
safety" is *required*. And please don't post those "foo(1U); // error"
any more, they are *not* the real world problems. What problem is out
there which requires you to make calling 'foo(int)' illegal with an
unsigned argument and is not already flagged by the compiler?
Please be specific.
> so as
> the compiler can help us avoid mistakes and thus bugs in our code. Why a
> library solution isn't better: Because it would be too complex and more
> limited, in comparison to the keyword based solution".
V
Just like
double d = 5;
is valid C++98/03, but with
only double d = 5;
won't compile. So why should
only const char * const p = "Hello, world!";
compile then? Any reason for this exception?
>> But a void pointer often is used pointing to raw memory, like in memory
>> allocators. Why do you want to propose a general type safety mechanism
>> and then forbid any useful usage?
>
>
> The void pointers were designed to point anywhere. Assigning a void
> pointer value to another type pointer variable, always requires a cast
> under C+98/03, and keyword "only" will not interfere with that.
> In other words, void pointers are designed to be unsafe (they point to
> an object of *any* type), so they cannot be used together with keyword
> "only".
But "only" is designed to make things more safe. Why not allow making an
unsafe type more safe by allowing "only void*", so that specific
pointers "T*" won't be implicitly convertible to it?
--
Thomas
BTW, it's not "assignment". It's initialisation. Just so we're on the
same page.
ITYM fewer. :)
In comp.lang.c one can find people who ask "why do we need C++"?
They "do not need" even function overloading to be adopted in C.
Uh... I am slow today. Were you making some point with that? Why
don't we add SQL query handling to C++ preprocessor? Or image
recognition capabilities? The existence of the feature elsewhere or
even its niceness is not enough justification to include it in the language.
So, let's start over. What problem do you solve with your addition to
the language that cannot be solved with already existing mechanisms?
More type safety means fewer programming errors. Do you agree with this?
...and even more type safety means even fewer programming errors, right?
Does that mean that strongly typed language with no implicit conversions
provides full protection against programming errors? No. So, I can
only agree with your statement to some degree. To what degree, you'd
ask. And I'd say, to the degree that C++ *already has*. More *than
already exists in the language* does *not* mean fewer errors. At this
point in C++'s development as a language *I* don't see the need in what
you're proposing. (I guess by now you've gathered that much). Now, you
have a change (this is, like, the umpteenth time I'm asking about it) to
prove to me that there exists *a problem*, a *concrete* problem, that
your change would help solve, and that cannot be solved by the existing
mechanisms of the language. And every time I ask about it, you start
puffing hot air about "type safety" and wave your arms around. This is
the last time, after which, if I don't read a coherent reply to my
inquiry, I'll consider the discussion *over*, and advise you to take up
the career in politics, where there is no responsibility, only
arm-waving and hot air. And I'll have to probably killfile you as a
troll. Nothing personal.
Do you understand what I'm asking?
At http://en.wikipedia.org/wiki/Comparison_of_programming_languages, check the second table about type safety
and C++.
I have already provided some examples from the current state of the proposal, but if you do not consider them
as type-safety examples that reduce the risk of errors, ==> perhaps you should wait until the proposal gets
more complete (and covers Object Oriented programming for example), and thus more examples will be given then.
Here are some examples, given the current state of the proposal, including some principles that I will add
tomorrow or later to the web page of the proposal:
Example 1:
class SomeClass
{
public:
SomeClass(int);
};
int main()
{
SomeClass obj1= 5; // OK, "only" is not used
SomeClass obj2= obj1; // OK, "only" is not used
only SomeClass obj3= 5; // Compiler Error.
only SomeClass obj4(5); // OK
only SomeClass obj5= obj1; // OK
int x; // OK, "only" is not used
only int i1; // error, "only" objects must be initialised always.
only int i2= 5; // OK
}
Example 2:
char *p= "Text"; // OK, "only" is not used
only char *p= "Text"; // Compiler Error
only const char *p= "Text"; // OK
only const char * const p= "Text"; // OK
char * const p= "Text"; // OK,"only" is not used
only char * const p= "Text"; // Compiler Error
The text, which is a work in progress, can be found here:
http://www.cpp-software.net/documents/cpp_only_proposal.html
(press Ctrl-Refresh in your browser, to make sure you see the most recent version of the page).
Any comments, corrections and contributions are welcomed.
As mentioned in the page, anyone that contributes to the proposal and wishes to take credit for his
contributions, if the proposal gets completed, he can follow the directions mentioned at the end of the page.
Thanks.
Have you also checked http://en.wikipedia.org/wiki/Type_safety and
http://en.wikipedia.org/wiki/Type_system#Safely_and_unsafely_typed_systems,
where it is described what is meant by type safety?
When you do, you will see that implicit conversions do not affect type
safety but that the lack of type safety in C and C++ is the result of
the unrestricted use of pointers that C and C++ allow combined with
the manual memory management.
Bart v Ingen Schenau
Thank you for the links. The proposal is actually a compile-time type-safety feature, and I have just updated
the web page to reflect that.
From the first link "Type safety", I think the following (which are not all the features mentioned in that
page) are accomplished so far (the proposal is a work in progress), without sacrificing the expressiveness of
C++98/03:
"most definitions involve the use of a type system to prevent certain erroneous or undesirable program
behavior (called type errors)".
"The enforcement can be static, catching potential errors at compile time, or dynamic, associating type
information with values at run time and consulting them as needed to detect imminent errors, or a combination
of both".
"The behaviors classified as type errors by a given programming language are usually those that result from
attempts to perform an operation on some values, that is not appropriate to their data types.
[...]
, while others consider any contravention of the programmer's intent (as communicated via typing annotations)
to be erroneous and deserving of the label "unsafe"".
"In the context of static type systems, type safety usually involves (among other things) a guarantee that the
eventual value of any expression will be a legitimate member of that expression's static type".
"Most statically-typed languages provide a degree of type safety that is strictly stronger than memory safety,
because their type systems enforce the proper use of abstract data types defined by programmers even when this
is not strictly necessary for memory safety or for the prevention of any kind of catastrophic failure".
The last one is one I am thinking about currently:
"A well typed program never gets "stuck", i.e., never gets into an undefined state where no further
transitions are possible".
This means we must have all compile-time type-safe variables initialised with a value.
Example:
int x; // OK, "only" is not used.
only int i1; // Error, "only" objects must be initialised always.
only int i2= 5; // OK
Regarding the second link "Safely and unsafely typed systems", I think the keyword "only", compile-time
type-safety solution accomplishes this.
More specifically I think it accomplishes in a high degree, the following:
"A third way of categorizing the type system of a programming language uses the safety of typed operations and
conversions. Computer scientists consider a language "type-safe" if it does not allow operations or
conversions which lead to erroneous conditions".
I agree with Viktor and Bart and consider this as a proposal without
any reasonable motivation. C++ type system is extremely strong except
those cases described by Bart. Let's close this discussion.
May I ask if you consider the new use of keyword "auto" in C++0x, necessary then?
Sure. One of the real problems is to express a type of return value of
template function. For example, try to store a result of "bind"
function from Boost.Bind library into some variable. Even if you
succeeded after few hours (most probably - days) of source code
investigation, replace that function with Boost.Lambda and you will
have to start all over again.
Here is some code example:
class A {
int i;
public:
A(int ii) : i(ii) {};
void set_i(int x) { i = x; }
};
A a;
__WHAT_TYPE_GOES_HERE__??? my_foo = bind(&A::set_i, ref(a), _1)
Please read more at http://en.wikipedia.org/wiki/C%2B%2B0x
The 'auto' keywords solves a real problem, that of otherwise having to repeat a
very long-winded, sometimes thousands of characters, and sometimes in practice
unknowable, type designation.
You
* haven't provided any use case for your 'only' keyword, you have
* ignored articles (including mine and Jeff's) showing how to easily do the
same within the current language, and you have
* multi-posted the discussion to two different groups plus web site.
Now I could easily put up some use cases convincing most people that this
/functionality/ (but not the keyword proposal) is needed, and it amazes me that
you, who makes such a proposal, has been unable to come up with them.
Be that as it may -- it's an honest thing and not unusual that the example
generator circuit refuses to come up with anything even though one remembers
having to deal with such (vaguely) earlier -- you really shouldn't have
ignored articles showing alternatives to your proposal.
That's a good way to be ignored in turn.
Multi-posting and web'ifying, which was the second measure you took in that
direction, is perhaps just as effective for that.
Cheers & hth.,
- Alf
--
Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
No ads, and there is some C++ stuff! :-) Just going there is good. Linking
to it is even better! Thanks in advance!
Might I suggest something?
After having reviewed your website it's clear to me that you're
basically a beginner. You might be past the tutorial stage, to the
point of actually being able to answer questions for other beginners,
but you've got a really long way to go. You not only need deeper
understanding of programming in C++ but also in effectively writing
technical specs and articles. You're also obviously lacking in the
politics and persuasion skills you would need to address an
international committee.
My suggestion is that perhaps attempting to make this major leap to
experthood without the experience and knowledge needed to succeed is a
mistake. My other suggestion is that perhaps you should consider more
thoughtfully the statements of experts you've heard from here in this
thread.
My final suggestion is to note that the STD committee will probably try
being polite about telling you to bugger off, maybe, but if you persist
and insist like you've done here you're going to make a huge ass of
yourself...just as you've done here.
I'd say it's worth the practice but you're not listening to anyone so
it's basically a waste of everyone's time.
At first I have to note that we are having an interesting friendly discussion about programming, and not a
controversy.
Well, I think one may specify the returned value in the style:
template <class ReturnType, class T>
ReturnType SomeFunction(const T& x)
{
ReturnType someValue;
// Do things with x
return someValue; // someValue is of type ReturnType
}
int main()
{
double x= SomeFunction<double>(5);
}
Regarding "only" proposal, this case shows me why the type-safety of returned value is important, a thing that
someone questioned elsewhere in the thread (just checked, Noah Roberts).
Regarding multiposting, why is it forbidden to post to relevant groups for a subject?
Reagrding "webifying", I keep my proposal as a web page, accessible to me and to all with whom I discuss, so
as to have a specific uptodate reference for my proposal. Why is this bad? Should I post my whole proposal
with its new additions, modifications and corrections to the thread, at every change I make?
Third, I am not ignoring anyone. I was provided with a template solution "else-thread", which did not compile
with g++, and I did not get a corrected reply. May you provide the messages I "ignored"?
>> __WHAT_TYPE_GOES_HERE__??? my_foo = bind(&A::set_i, ref(a), _1)
>>
> At first I have to note that we are having an interesting friendly
> discussion about programming, and not a controversy.
>
>
> Well, I think one may specify the returned value in the style:
>
>
> template <class ReturnType, class T>
> ReturnType SomeFunction(const T& x)
> {
> ReturnType someValue;
>
> // Do things with x
>
> return someValue; // someValue is of type ReturnType
> }
>
>
> int main()
> {
> double x= SomeFunction<double>(5);
> }
This is a perfect example of what I mean. I think people are getting
upset here because it seems you are ignoring them when I think the real
problem is that you don't actually understand the replies. You just so
completely missed the point that it's pretty clear, to me at least, that
you simply don't know anything about what you're trying to talk about.
Of course I consider all the statements here, that's why I created this discussion thread.
> My final suggestion is to note that the STD committee will probably try
> being polite about telling you to bugger off, maybe, but if you persist
> and insist like you've done here you're going to make a huge ass of
> yourself...just as you've done here.
>
> I'd say it's worth the practice but you're not listening to anyone so
> it's basically a waste of everyone's time.
Having you disagreeing with the proposal, doesn't mean that I have to agree with you. But I did not say the
proposal will ever get completed.
In fact if you notice at the bottom of the page:
http://www.cpp-software.net/documents/cpp_only_proposal.html
I have been mentioning since some time:
"It means that everyone who contributes to this proposal, and he wishes to take credit for his contribution,
his personal information will be included in the final text of the proposal, ==> if the proposal becomes
complete".
So I am not sure if the proposal gets completed. It may be unneeded indeed, or it may turn to something else,
like increasing compiler warnings in specific cases. It is something like an experiment project which may turn
to something useful, but it may not.
What is certain is that in the end of the process, if it does not get completed, I will provide a pdf with the
proposal as it will be then, probably under GNU Free Documentation License (as a free document).
It may be useful for future use of someone else, for something similar or something else.
It's not forbidden.
It's just very counter-productive, especially when none of threads refer to the
others.
As to the "why" I've given you a link earlier, in the other group you posted to.
> Reagrding "webifying", I keep my proposal as a web page, accessible to
> me and to all with whom I discuss, so as to have a specific uptodate
> reference for my proposal. Why is this bad? Should I post my whole
> proposal with its new additions, modifications and corrections to the
> thread, at every change I make?
That would be a good idea for a new proposal. And then not make small changes.
Versions.
> Third, I am not ignoring anyone. I was provided with a template solution
> "else-thread", which did not compile with g++, and I did not get a
> corrected reply. May you provide the messages I "ignored"?
Search for my name and for Jeff Schwab in any archive of this thread.
The new use of auto is not strictly necessary, but it does enable a
style of programming that would otherwise be impractical. This is one
of those cases where two different programming styles supported by C++
clash, in this case procedural and generative.
The result of an expression of arbitrarily complicated static type may
be passed to a function template, such that the type will be deduced by
the compiler, a custom function generated, and the type identified by a
nice, short template-parameter. In fact, this is the common use model
for boost::bind and boost::lambda.
The problem is that this approach effectively imposes a functional style
of programming. Since C++ is meant to be a multiparadigm language, it
should also support procedural programming of the sort common in C. The
new use of auto exists to enable procedural use of objects whose static
types are automatically generated, and may not be known at the time the
procedural code is written. Even if you know what static type
some_library::bind generates in a given context today, that type should
be free to evolve, without requiring syntactic changes in client code.
Just search in newsgroups at google, the word "cross-posting":
http://groups.google.gr/groups/search?hl=en&q=crossposting&qt_s=Search+Groups
I support the notion of multi-posting and not cross-posting, because at some point (including the beginning)
the discussion may become offtopic, while at the same time, people who consider cross-posting "bad" and
multi-posting "good" like me, post a reply only to "their" newsgroup (I don't follow this practice myself).
>
>
>> Reagrding "webifying", I keep my proposal as a web page, accessible to
>> me and to all with whom I discuss, so as to have a specific uptodate
>> reference for my proposal. Why is this bad? Should I post my whole
>> proposal with its new additions, modifications and corrections to the
>> thread, at every change I make?
>
> That would be a good idea for a new proposal. And then not make small
> changes. Versions.
Well, I have news for you. There is a new thing called the web, which is more useful than this practice. In
fact, I considered creating a wiki page for the proposal, so as people to be able to contribute easily, but I
left that idea aside so far.
An updated web page is a better reference than individual messages with the same stuff, especially for
discussions in moderated newsgroups and forums, where messages wait for approval, and other people reply to
something you have already changed.
In fact, I began this discussion thread with your recommended approach, and then it became obvious that a web
page is far better for this.
>
>
>> Third, I am not ignoring anyone. I was provided with a template
>> solution "else-thread", which did not compile with g++, and I did not
>> get a corrected reply. May you provide the messages I "ignored"?
>
> Search for my name and for Jeff Schwab in any archive of this thread.
I will do it and post replies.
Your code above is interesting, but it doesn't work for pointers:
template< typename T >
class Only
{
private:
T myValue;
template< typename U > Only( U v ); // No constr. from other types.
public:
// STATIC_ASSERT( that T is built-in type or something like that )
Only( T v ): myValue( v ) {}
T value() const { return myValue; }
operator T () const { return value(); }
};
int main()
{
int array= {};
Only<int *> pInt= &array[0];
}
Alf P. Steinbach wrote:
>
>> Regarding multiposting, why is it forbidden to post to relevant groups for a subject?
>
> It's not forbidden.
>
> It's just very counter-productive, especially when none of threads refer to the others.
>
> As to the "why" I've given you a link earlier, in the other group you posted to.
Just search in newsgroups at google, the word "cross-posting":
http://groups.google.gr/groups/search?hl=en&q=crossposting&qt_s=Search+Groups
I support the notion of multi-posting and not cross-posting, because at some point (including the beginning)
the discussion may become off-topic ==> for a newsgroup, while at the same time, people who consider
cross-posting "bad" and multi-posting "good" like me, post a reply only to "their" newsgroup (I don't follow
this practice myself).
>
>
>> Reagrding "webifying", I keep my proposal as a web page, accessible to me and to all with whom I discuss,
so as to have a specific uptodate reference for my proposal. Why is this bad? Should I post my whole proposal
with its new additions, modifications and corrections to the thread, at every change I make?
>
> That would be a good idea for a new proposal. And then not make small changes. Versions.
Well, I have news for you. There is a new thing called the web, which is more useful than this practice. In
fact, I considered creating a wiki page for the proposal, so as people to be able to contribute easily, but I
left that idea aside so far.
An updated web page is a better reference than individual messages with the same stuff, especially for
discussions in moderated newsgroups and forums, where messages wait for approval, and other people reply to
something you have already changed.
In fact, I began this discussion thread with your recommended approach, and then it became obvious that a web
page is far better for this.
>
>
>> Third, I am not ignoring anyone. I was provided with a template solution "else-thread", which did not
compile with g++, and I did not get a corrected reply. May you provide the messages I "ignored"?
>
> Search for my name and for Jeff Schwab in any archive of this thread.
This is interesting. Added a quick fix to behave as the stored type in all situations:
#include <iostream>
template<class Value_type>
class only
{
Value_type m_value;
template<class U> only(U);
public:
typedef Value_type value_type;
typedef Value_type& reference;
only(value_type value)
: m_value( value ) { }
value_type value() const {
return m_value;
}
// ==> quick fix for all operations requiring to behave as the stored type
operator Value_type()
{
return m_value;
}
};
int main()
{
using namespace std;
int intArray[10]= {};
only<int *>pInt= intArray; // It works, that's nice
double doubleArray[10]= {};
only<double *>pDouble= doubleArray; // It works, that's nice
only <double *>pDouble2= pDouble; // It works, that's nice
cout<< *pDouble<< endl;
}
Why hasn't this grown up for a proposal?
Perhaps some people were right, I did not pay much attention. I repost the code from another message of mine
with a "quick fix" for some cases:
template<class Value_type>
class only
{
Value_type m_value;
template<class U> only(U);
public:
typedef Value_type value_type;
typedef Value_type& reference;
only(value_type value)
: m_value( value ) { }
value_type value() const {
return m_value;
}
// ==> quick fix for all operations requiring to behave as the stored type
operator Value_type()
{
return m_value;
}
};
Why didn't this grow up for a proposal?
> // ==> quick fix for all operations requiring to behave as the
> stored type
> operator Value_type()
> {
> return m_value;
> }
> };
That's not a "fix", and it won't always behave the same way as the
stored type.
> Why hasn't this grown up for a proposal?
Because it's trivial to write, and never strictly necessary.
That's a "quick fix", because we can define std::ostream & operator<<(std::ostream &); member function for
this,and other relevant functions/member functions for other operations.
It will work in all cases when the value is read but not modified.
>
>> Why hasn't this grown up for a proposal?
>
> Because it's trivial to write, and never strictly necessary.
I don't think it is trivial to write for all situations.
Where did you find this template, did you think it up yourself?
Jeff Schwab wrote:
> Ioannis Vranos wrote:
>
>> // ==> quick fix for all operations requiring to behave as the stored type
>> operator Value_type()
>> {
>> return m_value;
>> }
>> };
>
> That's not a "fix", and it won't always behave the same way as the stored type.
==> That's a "quick fix", because we can define std::ostream & operator<<(std::ostream &objOstream, const
only<Value_type> &) function for this,and other relevant functions/member functions for other operations.
It will work in all cases when the value is read but not modified.
>
>> Why hasn't this grown up for a proposal?
>
> Because it's trivial to write, and never strictly necessary.
I don't think it is trivial to write for all situations.
Anyway, I added a bit more functionality. The template code as it currently is:
template <class Value_type>
class only;
template <class Value_type>
inline std::ostream & operator<<(std::ostream &objOstream, const only<Value_type> &obj)
{
using namespace std;
return objOstream<< obj.value();
Note that in spite of the misleading name, 'array' is not an entity that can be
indexed.
> }
What do you mean by "doesn't work"?
#include <iostream>
template <class Value_type>
class only;
template <class Value_type>
inline std::ostream & operator<<(std::ostream &objOstream, const only<Value_type> &obj)
{
return objOstream<< obj.value();
}
template <class Value_type>
class only
{
Value_type m_value;
template<class U> only(U);
public:
typedef Value_type value_type;
typedef Value_type& reference;
only(value_type value): m_value( value ) { }
value_type value() const { return m_value; }
};
// An example of completely type-safe code:
#include <iostream>
only<double> somefunc()
{
only<double> value= 1.0;
// Perform some operations
return value;
}
int main()
{
using namespace std;
only<double> result= somefunc();
only<int> i= static_cast<only<int> >(result); // ==> It fails
}
We can't initialize or assign the value of an only<double> object to an only<int> object explicitly, by using
a cast.
I made a typo mistake. The code works:
template< typename T >
class Only
{
private:
T myValue;
template< typename U > Only( U v ); // No constr. from other types.
public:
// STATIC_ASSERT( that T is built-in type or something like that )
Only( T v ): myValue( v ) {}
T value() const { return myValue; }
operator T () const { return value(); } // => Unsafe solution
};
int main()
{
int array[10]= {};
Only<int *> pInt= &array[0];
}
--
Ioannis A. Vranos
C95 / C++03 Developer
s/We/Ioannis/g
There will always be something you can wish for that some existing class doesn't
provide.
In such case, if you're unable to implement the wished for functionality it
generally doesn't mean the existing class is bad.
I am trying to port the completely compile-time type-safe code, to the use of this class:
// An example of completely type-safe code:
#include <iostream>
only double somefunc()
{
only double value= 1.0;
// Perform some operations
return value;
}
int main()
{
using namespace std;
only double result= somefunc();
only int x= static_cast<int>(result);
cout<< x<< endl;
only char c= 'a';
only signed char sc= 4HH;
only unsigned char uc= 4HHU;
only signed char schar= static_cast<signed char>(c);
}
Here is what I made so far:
#include <iostream>
template <class Value_type>
class only;
// It makes the object work with cout, provided the type Value_type is
// supported by cout.
template <class Value_type>
inline std::ostream & operator<<(std::ostream &objOstream, const only<Value_type> &obj)
{
return objOstream<< obj.value();
}
template <class Value_type>
class only
{
Value_type m_value;
/* template<class U> only(U); // No constr. from other types.*/
public:
typedef Value_type value_type;
typedef Value_type& reference;
only(value_type value): m_value( value ) { }
value_type value() const { return m_value; }
// Makes casts, assignment and initialization to float/const float to work
operator const float() const { return static_cast<const float>(m_value); }
// Makes casts, assignment and initialization to double/const double to work
operator const double() const { return static_cast<const double>(m_value); }
// Makes casts, assignment and initialization to long double/const long double to work
operator const long double() const { return static_cast<const long double>(m_value); }
// Makes casts, assignment and initialization to char/const char to work
operator const char() const { return static_cast<const char>(m_value); }
// Makes casts, assignment and initialization to signed char/const signed char to work
operator const signed char() const { return static_cast<const signed char>(m_value); }
// Makes casts, assignment and initialization to unsigned char/const unsigned char to work
operator const unsigned char() const { return static_cast<const unsigned char>(m_value); }
// Makes casts, assignment and initialization to short/const short to work
operator const short() const { return static_cast<const short>(m_value); }
// Makes casts, assignment and initialization to unsigned short/const unsigned short to work
operator const unsigned short() const { return static_cast<const unsigned short>(m_value); }
// Makes casts, assignment and initialization to int/const int to work
operator const int() const { return static_cast<const int>(m_value); }
// Makes casts to unsigned/const unsigned to work
operator const unsigned() const { return static_cast<const unsigned>(m_value); }
// Makes casts, assignment and initialization to long/const long to work
operator const long() const { return static_cast<const long>(m_value); }
// Makes casts, assignment and initialization to unsigned long/const unsigned long to work
operator const unsigned long() const { return static_cast<const unsigned long>(m_value); }
};
// An example of completely type-safe code:
#include <iostream>
only<double> somefunc()
{
only<double> value= 1.0;
// Perform some operations
return value;
}
int main()
{
using namespace std;
only<double> result= somefunc();
only<int> x= static_cast<int>(result);
cout<< x<< endl;
only<char> c= 'a';
only<signed char> sc= 4;
only<unsigned char> uc= 4;
only<signed char> schar= static_cast<signed char>(c);
}
I think this approach is promising, with the introduction of the new prefixes:
"New prefixes for signed char, unsigned char, short, unsigned short constants:
1. “HH” and “hh” for signed char constants.
2. “HHU” and “hhu” for unsigned char constants.
3. “H” and “h” for short constants.
4. “HU” and “hu” for unsigned short constants.
What do you think?
#include <iostream>
template <class Value_type>
class only;
// It makes the object work with cout, provided the type Value_type is
// supported by cout.
template <class Value_type>
inline std::ostream & operator<<(std::ostream &objOstream, const only<Value_type> &obj)
{
return objOstream<< obj.value();
}
template <class Value_type>
class only
{
Value_type m_value;
/* template<class U> only(U); // No constr. from other types.*/
public:
typedef Value_type value_type;
typedef Value_type& reference;
only(value_type value): m_value( value ) { }
value_type value() const { return m_value; }
// Makes casts, assignment and initialization to float/const float to work
operator const only<float>() const { return static_cast<const float>(m_value); }
// Makes casts, assignment and initialization to double/const double to work
operator const only<double>() const { return static_cast<const double>(m_value); }
// Makes casts, assignment and initialization to long double/const long double to work
operator const only<long double>() const { return static_cast<const long double>(m_value); }
// Makes casts, assignment and initialization to char/const char to work
operator const only<char>() const { return static_cast<const char>(m_value); }
// Makes casts, assignment and initialization to signed char/const signed char to work
operator const only<signed char>() const { return static_cast<const signed char>(m_value); }
// Makes casts, assignment and initialization to unsigned char/const unsigned char to work
operator const only<unsigned char>() const { return static_cast<const unsigned char>(m_value); }
// Makes casts, assignment and initialization to short/const short to work
operator const only<short>() const { return static_cast<const short>(m_value); }
// Makes casts, assignment and initialization to unsigned short/const unsigned short to work
operator const only<unsigned short>() const { return static_cast<const unsigned short>(m_value); }
// Makes casts, assignment and initialization to int/const int to work
operator const only<int>() const { return static_cast<const int>(m_value); }
// Makes casts to unsigned/const unsigned to work
operator const only<unsigned>() const { return static_cast<const unsigned>(m_value); }
// Makes casts, assignment and initialization to long/const long to work
operator const only<long>() const { return static_cast<const long>(m_value); }
// Makes casts, assignment and initialization to unsigned long/const unsigned long to work
operator const only<unsigned long>() const { return static_cast<const unsigned long>(m_value); }
};
// An example of completely type-safe code:
#include <iostream>
only<double> somefunc()
{
only<double> value= 1.0;
// Perform some operations
return value;
}
int main()
{
using namespace std;
// double result1= somefunc(); // This is an error, great!
only<double> result= somefunc();
only<int> x= static_cast<only<int> >(result);
cout<< x<< endl;
only<char> c= 'a';
only<signed char> sc= 4;
only<unsigned char> uc= 4;
only<signed char> schar= static_cast<only<signed char> >(c);
The latest code that works:
#include <iostream>
template <class Value_type>
class only;
// It makes the object work with cout, provided the type Value_type is
// supported by cout.
template <class Value_type>
inline std::ostream & operator<<(std::ostream &objOstream, const only<Value_type> &obj)
{
return objOstream<< obj.value();
}
template <class Value_type>
class only
{
Value_type m_value;
/* template<class U> only(U); // No constr. from other types.*/
public:
typedef Value_type value_type;
typedef Value_type& reference;
only(value_type value): m_value( value ) { }
value_type value() const { return m_value; }
// Makes casts, assignment and initialization to float/const float to work
operator const float() const { return static_cast<const float>(m_value); }
// Makes casts, assignment and initialization to double/const double to work
operator const double() const { return static_cast<const double>(m_value); }
// Makes casts, assignment and initialization to long double/const long double to work
operator const long double() const { return static_cast<const long double>(m_value); }
// Makes casts, assignment and initialization to char/const char to work
operator const char() const { return static_cast<const char>(m_value); }
// Makes casts, assignment and initialization to signed char/const signed char to work
operator const signed char() const { return static_cast<const signed char>(m_value); }
// Makes casts, assignment and initialization to unsigned char/const unsigned char to work
operator const unsigned char() const { return static_cast<const unsigned char>(m_value); }
// Makes casts, assignment and initialization to short/const short to work
operator const short() const { return static_cast<const short>(m_value); }
// Makes casts, assignment and initialization to unsigned short/const unsigned short to work
operator const unsigned short() const { return static_cast<const unsigned short>(m_value); }
// Makes casts, assignment and initialization to int/const int to work
operator const int() const { return static_cast<const int>(m_value); }
// Makes casts to unsigned/const unsigned to work
operator const unsigned() const { return static_cast<const unsigned>(m_value); }
// Makes casts, assignment and initialization to long/const long to work
operator const long() const { return static_cast<const long>(m_value); }
// Makes casts, assignment and initialization to unsigned long/const unsigned long to work
operator const unsigned long() const { return static_cast<const unsigned long>(m_value); }
};
// An example of completely type-safe code:
#include <iostream>
only<double> somefunc()
{
only<double> value= 1.0;
// Perform some operations
return value;
}
int main()
{
using namespace std;
double result1= somefunc(); // ==> It works, must be fixed.
only<double> result= somefunc();
only<int> x= static_cast<int>(result);
cout<< x<< endl;
only<char> c= 'a';
only<signed char> sc= 4;
only<unsigned char> uc= 4;
only<signed char> schar= static_cast<signed char>(c);
Well. I'm sorry but it seems like much complexity for little gain. Complexity
seems to stem from trying to adhere to a nebuluous specification, what the
client code /might/ want allowed and not allowed.
A better approach/design could be to leave that decision to the client code.
E.g. as in <url: http://code.google.com/p/mili/wiki/PromotionDisable>.
Cheers & hth.,
- Alf
--
You are mistaken. That goal can not be accomplished unless you turn
the proposal completely around: Make the 'only' semantics the default
and provide special syntax for performing unsafe operations. This
would take C++ in the direction that Ada has taken.
Did you also notice that, in the table you referenced, FORTRAN and
Python are listed as type-safe languages? TTBOMK, both languages allow
implicit conversions of the style you want to disallow with the 'only'
proposal.
Bart v Ingen Schenau
Given that fact, there is no hope left to make C++ a type-safe
language.
Additionally, type-safety is not affected by the existence of (well-
defined) implicit conversions.
The declarations
int i = 4.2;
double d = 42;
are both perfectly type-safe.
Regarding the new use of the keyword 'auto' that you ask about else-
thread, that just makes it possible to declare a variable of a type
that you as programmer can't spell out.
This new use of auto does not in any way affect type safety, because
the compiler knows exactly which type the object has and performs all
the normal type checking that it would have done if the programmer had
spelled the type out.
Bart v Ingen Schenau
#include <iostream>
template <class ValueType>
class only;
// It makes the object work with cout, provided the type ValueType is supported by cout.
template <class ValueType>
inline std::ostream & operator<<(std::ostream &objOstream, const only<ValueType> &obj)
{
return objOstream<< obj.getValue();
}
// It converts between compatible only<T> types
template<class NewType, class OnlyType>
inline NewType type_cast(const OnlyType &obj)
{
return static_cast<NewType>(obj.getValue());
}
// Original class provided by Jeff Schwab <je...@schwabcenter.com>
template <class ValueType>
class only
{
ValueType localValue;
template<class U> only(U); // No constr. from other types.
public:
typedef ValueType value_type;
typedef ValueType& reference;
only(value_type value): localValue( value ) { }
const value_type &getValue() const { return localValue; }
};
// An example of completely type-safe code:
#include <iostream>
only<double> somefunc()
{
// only<double> value= 1.1F; // It produces an error, great!
only<double> value= 1.1;
// Perform some operations
return value;
}
int main()
{
using namespace std;
only<char> c= 'a';
// It doesn't work without a cast, interesting! (because 4 is int)
only<signed char> sc= static_cast<signed char>(4);
// It doesn't work without a cast, interesting! (because 4 is int)
only<unsigned char> uc= static_cast<unsigned char>(4);
// It requires an explicit conversion between different types
only<signed char> schar= type_cast<signed char>(c);
// It doesn't work without a cast, interesting! (because 4 is int)
only<short> s= static_cast<short>(4);
// It doesn't work without a cast, interesting! (because 4 is int)
only<unsigned short> su= static_cast<unsigned short>(4);
// It doesn't work without a cast, interesting! (because 4 is int)
only<long> l= static_cast<long>(4);
// It doesn't work without a cast, interesting! (because 4 is int)
only<unsigned long> lu= static_cast<unsigned long>(4);
only<double> result= somefunc();
only<int> x= type_cast<int>(result);
cout<< x<< endl;
// double result2= somefunc(); // It produces an error, great!
// only<int> x2= result; // It produces an error, great!
Yes, I did. Someone has since posted a link on this thread to a more
sophisticated "Restrict" template.
Make sure you clear the cache of your browser.
The old proposal, making use of the "keyword" only (abandoned) can be found here:
http://www.cpp-software.net/documents/cpp_only_proposal_old.html
This proposal is being "ported" to the template class "only" proposal.
EWWW!!!! Not only is this a really long list of operators, you can't
extend it to new types (such as complex_number).
Two ways you could solve this problem:
template < typename T >
struct only {
...
template < typename Other >
explicit only( only<Other> const& other ) : value(other.value)
{
BOOST_STATIC_ASSERT((is_convertable<Other, T>::value));
}
};
only<int> x = only<int>(result);
Option two:
template < typename T >
struct only
{
...
template < typename Return >
Return cast() const
{
BOOST_STATIC_ASSERT((is_convertable< Return, T >::value));
return value;
}
};
template < typename T, typename R >
R only_cast(only<T> const& o)
{
return static_cast<T>(o); // use cast operator you've made for T.
}
only<int> x = only_cast<int>(result);
There's other ways I'm sure. You just need to analyze the problem.
> I think this approach is promising, with the introduction of the new
> prefixes:
>
> "New prefixes for signed char, unsigned char, short, unsigned short
> constants:
>
> 1. “HH” and “hh” for signed char constants.
>
> 2. “HHU” and “hhu” for unsigned char constants.
>
> 3. “H” and “h” for short constants.
>
> 4. “HU” and “hu” for unsigned short constants.
C++0x might let you do this:
http://en.wikipedia.org/wiki/C%2B%2B0x#User-defined_literals
This was preliminary code. You may find the latest implementation at
http://www.cpp-software.net/documents/cpp_only_proposal.html
However since the C++ standard committee will not be accepting new proposals for one year or more, this
project has low priority in my free time.
>
> Two ways you could solve this problem:
>
> template < typename T >
> struct only {
> ...
> template < typename Other >
> explicit only( only<Other> const& other ) : value(other.value)
> {
> BOOST_STATIC_ASSERT((is_convertable<Other, T>::value));
> }
> };
>
> only<int> x = only<int>(result);
>
> Option two:
>
> template < typename T >
> struct only
> {
> ...
>
> template < typename Return >
> Return cast() const
> {
> BOOST_STATIC_ASSERT((is_convertable< Return, T >::value));
> return value;
> }
> };
>
> template < typename T, typename R >
> R only_cast(only<T> const& o)
> {
> return static_cast<T>(o); // use cast operator you've made for T.
> }
>
> only<int> x = only_cast<int>(result);
>
> There's other ways I'm sure. You just need to analyze the problem.
Yes. Thank you for your suggestions, however I have to note that the implementation of this class and its
facilities may only depend on C++ standard library, and not on third-party libraries like boost.
>
>> I think this approach is promising, with the introduction of the new
>> prefixes:
>>
>> "New prefixes for signed char, unsigned char, short, unsigned short
>> constants:
>>
>> 1. “HH” and “hh” for signed char constants.
>>
>> 2. “HHU” and “hhu” for unsigned char constants.
>>
>> 3. “H” and “h” for short constants.
>>
>> 4. “HU” and “hu” for unsigned short constants.
>
> C++0x might let you do this:
> http://en.wikipedia.org/wiki/C%2B%2B0x#User-defined_literals
When C++ gets finalised and we get some decent implementations supporting it (this translates to years), I
will take a look at the new C++ facilities.
Thank you for your comments.
Best regards,