Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - DerSaidin

Pages: [1]
1
Ideas / Re: Switch statement
« on: August 30, 2015, 03:12:25 PM »
switch (x) {
case 1|2: ..
case 3|4 ..
}

I agree with chqrlie that this would be better achieved by multiple case statements.

Code: [Select]
switch (x) {
case 1:
case 2:
  ...
  break;
case 3:
case 4:
  ..
  break;
}

(Note: imo, case 1 wouldn't require any explicit fallthrough because there is no code there to fallthrough from.)

I also agree that for the other option , would be a better separator than |.

2
Ideas / Re: Unsigned char
« on: August 30, 2015, 02:59:58 PM »
I agree with char being uint8.

Imo:
  • uint8* and int* should be incompatible
  • uint8* and char* could be incompatible, but it doesn't matter much

Just because they happen to be the same size they should be compatible?
I think there is a reasonable argument to separate a number from a character.

I think it doesn't matter too much because explicit casting is still available if that is really the intention.

3
Ideas / Re: Enum classes
« on: August 30, 2015, 02:49:27 PM »
Hello,

I think the main advantage of enum classes in C++11 is better type safety. You can't just use enum values like integers anymore.

With more knowledge of the types, do you need the enum namespace explicit in the code to be unambiguous?
Does it actually remove any ambiguity?

Code: [Select]
State s2 = SomethingOtherThanState::Start;  // won't ever work anyway, it has to be in Start::

Is there any case were you don't know the type of the LHS, and having the enum type as part of the RHS would be necessary?

Although personally I wouldn't mind being overly explicit, even if unnecessary, and requiring the enum value to specifying the namespace  :)

4
Ideas / Re: Switch statement
« on: April 11, 2014, 04:05:09 PM »
I'd suggest a third option: the user MUST terminate each case with a break or fallthrough (whatever keyword that may use) or return. Then there is no default, it is always explicit.

5
Ideas / Re: D-language Modules/Imports
« on: March 24, 2014, 12:06:44 PM »
The differences you list are mainly syntax. In the interest of exploring more significant differences:

What are C2's advantages compared to D?
What is a project that you think C2 would be a better choice than D?

6
General Discussion / Re: Integer Literal checking
« on: March 24, 2014, 11:54:46 AM »
Option 2 seems reasonable to me.

Also keep in mind you will be able to allow more complex constant expressions later (if you find it needed), but it would be harder to take them away.

Being able to call functions and stuff with C++ constexpr is cool. What do you think of using the same rules as C++ constexpr?

7
Ideas / Re: Make increment operators statements, not expressions
« on: August 27, 2013, 02:06:51 PM »
Yes, I think that option c would produce the clearest code. But I don't think forcing this will
help in getting C2 accepted, since it also make the code a lot bigger. There are a lot of cases
where correct usage will increase readability, because less lines of code are needed.

Code: [Select]
i = v[i++];
i = v[i]; i++;
No extra lines, 3 characters bigger.

Is two statements on one line considered bad style? how is two side effects in one statement better?

Another point to consider is option c is a subset you can add to in a later version. Once there is a decent amount of C2 code you can't easily go back to option c.

The balance I'm trying to find is on one side restricting the language to remove things that
are error-prone (like i = v[i++]). On the other side, not trying to restrict too much, since that
won't help convincing current C programmers to change to C2 in the future.

That is a tricky one. C programmers like C because they don't want a language to restrict them, but the problem with C is it lets programmers make mistakes easily. The double edged sword. :)

This may belong in a separate thread; is C2's goal to replace C in practice?

8
Ideas / Re: Make increment operators statements, not expressions
« on: August 27, 2013, 10:41:20 AM »
I agree, I think it is something you can analyse. C compilers should probably do this and warn.

For C2, there are a few options:
a) define the behaviours
b) leave it undefined, rely on an analysis to disallow undefined behaviour
c) disallow increment as subexpressions, require explicit increment statement

I prefer c because it is the simplest and produces the clearest code.

9
Ideas / Make increment operators statements, not expressions
« on: August 26, 2013, 03:13:08 PM »
http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points

Increment operators used as subexpressions (++x; x++; --x; x--) can easily produce undefined behaviour (see examples in link).

To remove this possibility, I suggest making these only appear as entire statements, not subexpressions.
This could be done by making the return type of the operators void, or by only allowing these operators as statements in the grammar.

Examples from the stackoverflow link:
Code: [Select]
i = i++ * ++i ;  //invalid

i = v[i++];   //invalid

You can argue for making these sort of issues well defined, but I think it is clearest and simplest to require the negligibly longer and perfectly explicit alternative:
Code: [Select]
i = (i+1) * (i+2); // or whatever the actual intention was

i = v[i];
i++;

They should still be valid in the third part of a for loop, including multiple increments:
Code: [Select]
for (int a=1; a<10; a++, i++)

10
Implementation Details / C2 Grammar?
« on: August 25, 2013, 02:54:25 PM »

Is there a grammer for c2lang?

I couldn't see one anywhere on the site (wiki is 403?).
C2Parser.cpp comments have some productions, but it doesn't look like there is a complete grammar in the comments.


I grepped them out (on '::=' so I probably missed a few),
then I started completing it using productions from (or based on) the
C1X draft (see Annex A.2).

Code: [Select]
start ::=  package_declaration  top_level_list
// Should package need to be declared first?
// Should an emtpy file be allowed to compile, or does it need a package_declaration?
package_declaration ::= PACKAGE IDENTIFIER SEMICOLON
top_level_list ::=
top_level_list ::= top_level top_level_list
top_level ::= visibility_qualifier type_def
top_level ::= visibility_qualifier func_def
top_level ::= visibility_qualifier use_declaration
top_level ::= visibility_qualifier var_def
// Can variables be public? Alternative; require accessor/settor public function.
visibility_qualifier ::=
visibility_qualifier ::= PUBLIC
type_def ::= TYPE IDENTIFIER type_qualifier type_specifier
type_def ::= TYPE IDENTIFIER func_type
type_def ::= TYPE IDENTIFIER STRUCT LBRACE struct_block RBRACE
type_def ::= TYPE IDENTIFIER UNION LBRACE struct_block RBRACE
type_def ::= TYPE IDENTIFIER ENUM LBRACE enum_block RBRACE
struct_block ::=
struct_block ::= struct_member struct_block
struct_member ::= type_qualifier type_specifier IDENTIFIER SEMICOLON
struct_member ::= UNION LBRACE struct_block RBRACE IDENTIFIER SEMICOLON
type_def ::= access_specifier TYPE IDENTIFIER ENUM LBRACE enum_block RBRACE SEMICOLON
enum_block   ::= enum_block COMMA enum_member
enum_block   ::= enum_block COMMA
enum_block   ::= enum_member
enum_member ::= IDENTIFIER
enum_member ::= IDENTIFIER EQUALS constant_expression
func_type ::= FUNC type_qualifier single_type_specifier LPAREN full_param_list RPAREN
full_param_list ::=
full_param_list ::= param_list
full_param_list ::= param_list COMMA ELLIPSIS
param_list ::= param_declaration
param_list ::= param_list COMMA param_declaration
param_declaration ::= type_qualifier type_specifier IDENTIFIER param_default
param_default ::= EQUALS constant_expression
type_specifier ::= single_type_specifier
type_specifier ::= type_specifier array_specifier
func_def ::= FUNC type_qualifier single_type_specifier IDENTIFIER LPAREN full_param_list RPAREN compound_statement SEMICOLON
statement ::= labeled_statement
statement ::= compound_statement
statement ::= expression_statement
statement ::= selection_statement
statement ::= iteration_statement
statement ::= jump_statement
labeled_statement ::= IDENTIFIER COLON statement
labeled_statement ::= CASE constant_expression COLON statement
labeled_statement ::= DEFAULT COLON statement
compound_statement ::= LBRACE RBRACE
compound_statement ::= LBRACE block_item_list RBRACE
block_item_list ::= block_item
block_item_list ::= block_item_list block_item
block_item ::= statement
block_item ::= declaration
expression_statement ::= expression SEMICOLON
expression_statement ::= SEMICOLON
// compound_statement instead of statement for IF (C 6.8.4).
// This prevents ambiguous: if(a) if(b) X; else Y;
//  if(a) { if(b) X; else Y; }
//  if(a) { if(b) X; } else Y;
selection_statement ::= IF LPAREN expression RPAREN compound_statement
selection_statement ::= IF LPAREN expression RPAREN compound_statement ELSE compound_statement
iteration_statement ::= FOR LPAREN expression_statement expression_statement expression RPAREN statement
iteration_statement ::= FOR LPAREN expression_statement expression_statement RPAREN statement
jump_statement ::= GOTO identifier SEMICOLON
jump_statement ::= CONTINUE SEMICOLON
jump_statement ::= BREAK SEMICOLON
jump_statement ::= RETURN SEMICOLON
jump_statement ::= RETURN expression SEMICOLON
declaration ::= type_qualifier type_specifier IDENTIFIER var_initialization
var_def ::= type_qualifier type_specifier IDENTIFIER var_initialization SEMICOLON
init_value ::= constant_expression
init_value ::= LBRACE init_values RBRACE
init_values ::= init_values COMMA init_value
init_values ::= init_values COMMA
init_values ::= init_value

That is incomplete, but missing productions are probably mostly the same as the C spec.

Imo it is easiest to implement a parser from a grammar,  so I wonder if you already have one.

11
Ideas / Re: Preprocessor and Macros
« on: July 25, 2013, 10:51:37 AM »
Sometimes macro's just save you from typing. But like many other basic tools, their heavily abused.

Indeed, they are too easily abused and frequently abused.

I through about removing the macro-preprocessor from C2, but still haven't found a good solution
as alternative. One idea are semantic macros. You can define these like functions, but the main
difference with normal macro's is that they are expanded inside the AST (Abstract Syntax Tree)
and not in the source code. This way, everything can be checked. For example:
old and very bad way ;)
#define MAX(a,b) (a>b? a : b)

With semantic macros, this would be:
public macro MAX(a, b) {
   a>b? a : b;
}

The nice thing is that the compiler understands it a lot better and that
it can actually warn if used with the wrong a and b for example.

That use case is pretty much a function.

Expanding it in the style a macro achieves two things there:
  • Inlining for performance
  • Code is applicable for multiple types (generics/templates in other languages)

For the inlining performance case, I would argue that 1) that is an issue for optimizer, 2) the inline keyword should force it to occur.
Also, inlining the MAX in this example seems reasonable, but when the uses escalate to very large amounts of code being inlined it can become evil again.
The semantic macro in your example is an improvement.


Another use of macros I've seen, which is really an inlining issue, is for table gen type stuff.
Example:
http://hg.dersaidin.net/weaver/file/17e883a72fc6/base/code/game/spell_info.def
http://hg.dersaidin.net/weaver/file/17e883a72fc6/base/code/game/spell_shared.c#l352
But this could be done using a constant global to hold the data/table, and a for loop instead of a switch. I believe the reason for using macros instead is: to have a switch, which should gen more efficiently than a loop.
I think undefining and redefining macros like this would still be evil with semantic macros.

You could also argue this type of thing should be done using a tool like LLVM's tablegen.

The most common place macros are used for inlining is for constants. That is replaced with c++11 constexpr (or just const globals, I think it is really a pretty arbitrary difference).



Generics/templates in other languages could be described as "semantic macros", but they are are more strongly typed than the MAX code in your example:
Code: [Select]
template<typename T>                                                                           
T MAX(T a, T b) { return a > b ? a : b; } // a and b are both type T.

#include <iostream>

int main(int argc, char**argv) {
    int a = 4;
    int b = 9;
    float c = 4.99;
    float d = 9.52;
    std::cout << MAX(a, b) << std::endl;
    std::cout << MAX(c, d) << std::endl;

    // Error, they're not the same type
    std::cout << MAX(a, c) << std::endl;

    return 0;
}


All of the reasonable macro expansions uses I can think of are either
  • Inlining to work around optimizer failings
  • Generics

What other uses of macros expansions aren't totally evil?
There might be some, but I can't think of any others at the moment.

12
Ideas / Preprocessor and Macros
« on: July 24, 2013, 02:12:44 PM »
http://stackoverflow.com/questions/14041453/why-preprocessor-macros-are-evil-and-what-is-the-real-alternative-c11
In general, I agree macros are evil.

Remove the preprocessor? Modules address the main problem

Or at least remove macro expansions to source tokens, so #define only effects other preprocessor directives?

13
Ideas / Re: Syntax of const pointers
« on: July 24, 2013, 10:43:56 AM »
Now for the tricky part:
Code: [Select]
const int*
int const*
Both are equal and describe a pointer to an integer that cannot be changed. The pointer itself can be changed to point
at something else. Syntax here is already becoming more vague.

I think this is the main problem with const in C, the order of const is varying/inconsistent/different.
It becomes confusing when you usually use 'const int *', and you see 'int const *' and think it means something different. I think it would be an improvement to restrict to specific positioning.

3. Limit positioning
ansi-C  ->    C2
const intconst int
int constconst int
const int*const int*
int const *const int*
int* constint* const
const int* constconst int* const
const int * constconst int* const
const int * const *const int* const *
const int * const *constconst int* const * const

This positioning is what I usually see and write.
I think this would reduce confusion, and is compatible with C.

However, this is a bit inconsistent:
Code: [Select]
const int a = 4;
int * const b = &c;
The variables a and b are both constant, but in one case the const qualifier is before the type,
in the other case const is before the identifier and after the type.                                                                               

To make it more consistent, you could move the first const, so the const comes after the type it qualifies.
Parentheses shouldn't be needed, think of it as a tightly binding suffix operator.

4. Const qualifier after type
ansi-C  ->    C2
const intint const
int constint const
const int*int const *
int const *int const *
int* constint * const
const int* constint const * const
const int * constint const * const
((((int) const) *) const)  // parentheses to clarify ast structure
const int * const *int const * const *
((((int) const) *) const) *)  // parentheses to clarify ast structure
const int * const *constint const * const * const
(((((int) const) *) const) *) const)  // parentheses to clarify ast structure

Now the const qualifier is consistently after the type, and is still compatible with C.
It doesn't have the usual adjective-noun order if you read it left to right, but right to left is ideal:
Code: [Select]
int const * const X = &b;"X is a constant pointer to a constant int"

It could also be made consistent by always putting the const qualifer before the type.
This takes the * token as the position of the pointer type.

5. Const qualifier before type
ansi-C  ->    C2
const intconst int
int constconst int
const int*const int *
int const *const int *
int* constint const *
const int* constconst int const *
const int * constconst int const *
((const (int)) (const *))  // parentheses to clarify ast structure  :/
const int * const *const int const * *
const int * const * constconst int const * const *

This is consistent, and it is in the usual adjective-noun order (and the [probably] more common qualifier ordering use in C).
One disadvantage with this is that It breaks compatbility with C. I realize that C compatibility is not a goal, but it does make it less confusing for C developers, who are probably the main audience.

Also, the AST structure isn't nice/clear/elegant to me.



One of the features of type qualifiers is that they can be added to an existing type, you don't need to define a new type for the qualifier. For this reason I don't like Option 2.


If you don't know the language Options 3, 4 and 5 aren't as implicitly obvious as Option 1, but they're still simple and easy to apply once known and save syntactic cluttering of parentheses.


My preference is Option 4 for being consistent, C compatible, and nice to say aloud (by saying tokens right to left).

Pages: [1]