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 - bas

Pages: 1 ... 9 10 [11] 12 13 ... 15
151
Ideas / Struct Functions - part 2
« on: November 28, 2016, 09:08:33 AM »
I've been implementing some code using struct functions and must say I'm completely happy with the calling side. On the receiving side (the function itself), a patterns is appearing that might be avoided. Currently struct functions look like this:

Code: [Select]
func void myStruct_init(MyStruct* this) {
   this.a = 1;
   this.b = 2;
   // ..
}

This is just a small piece of code, but the thing that starts to itch in bigger functions is the frequent appearance of the this.
To make it feel more like (for example) a C++ class, we could add the struct members in the function namespace. Then all the
this keywords could go (unless ambiguous). This would have some consequences:

  • name duplicates between module and struct members is allowed (since can distinguish with module.a and this.a)
  • name duplication between struct members and function arguments is not allowed (cannot distinguish somehow)

I don't think since is a problem, since it's not a problem in object-oriented languages as well. Any feedback is welcome,

Cheers,
Bas

152
Ideas / Re: [Email suggestion No. 1] macros in C2
« on: July 22, 2016, 09:22:41 PM »
In your previous example about the factorial, there is no reason at all to use a macro,
since the compiler can figure out perfectly well if the function is pure (ie only depends on
the arguments and doesn't access globals). So the whole factorial(x) can be calculated at
compile time if a constant is used as argument.

For unit testing, I almost never use boolean expressions in macros, so instead of (for example)
Code: [Select]
assert_equal(a == b, "a is not b");

it's much better to use
Code: [Select]
assert_equals(a, b);
assert_greater(a ,b);
because the code can then immediately print something like: expected <x>, got <y>.

There might be other cases where a boolean expression is really needed, but I can't think
of them right now.. I'll spent some time thinking about this.

When thinking about the implementation, let's talk about the macro changing variables in the caller's environment,
eg: (the example is a bit contrived, but i hope the meaning is clear)
Code: [Select]
public macro increment_b_with(x) {
   b += x;
}
(In this case, b could also have been added as argument, but for the example it's not).
So when parsing the code, the macro is ok, but when it's used, there must be a variable
b in scope. If not, you ideally want a nice syntax error, like:

caller.c2:10 macro 'mod.increment_b_with' needs external identifier 'b'


One last idea is to let a developer impose some type restrictions. So for example an argument
must be type struct X. This does however come into the domain of regular functions..

153
General Discussion / Light-weight classes
« on: April 28, 2016, 09:38:34 PM »
There was recently a discussion on Embedded.com (http://www.embedded.com/electronics-blogs/break-points/4441819/Fixing-C).
On of the often heard ideas was C++, but without all the fluff. But something like lightweight classes.

C++ has (multiple)inheritance, no real interfaces (like Java), operator overloading, method overloading etc etc
If you just want the basics, eg a struct with functions, that should be possible to create. It's just syntactic sugar,
s
Code: [Select]
func void MyStruct::myfunction() {..}
just becomes:
Code: [Select]
func void myfunction(MyStruct* A) {..}

Of course, when you also want interfaces, it becomes harder.
And when you also want to use the same function name with different parameter types, it again becomes harder..

My conclusion is that any 'lightweight' class construction will quickly lead to a lot of fluff, because people except
all those features in languages with classes. So it might just be easier to just leave them out altogether...

154
Ideas / Re: Unsigned char
« on: February 10, 2016, 11:04:28 AM »
good discussions!

I think everyone agrees on the int8/uint8 stuff.
The question is which type to give X in:
Code: [Select]
X hello = "Hello World";
X is currently 'char' and in my opinion, should be used for strings. That said, We could make it unsigned since that
would be better (discussed already). However.... I recently read another book about Secure programming in C
(I can post the exact title for anyone interested) that explained why signed variables are used so often in C, even
for counting stuff. The reason is that negative (or -1) can then be used for error handling. Quite obvious of course,
but when you think about it, it really is so. So

Code: [Select]
int number = calculateNumber();
if (number == -1) {
   // error
}
The same goes for strings of course. The -1 value of char can be used to have a special case.

You propose that char (or at least char*) are used for strings, but how about the case of single chars?
Code: [Select]
char c = 'C'Would signed/unsigned be better here?

Your suggestion of changing 'int8' / 'uint8' to 'i8' and 'u8' is quite funny, since that is actually what C2 started with.
It is also what's used in Rust btw. I think there are even some discussions about that on this forum. We looked at
a lot of code with either the long or the shorter version and found the longer version more 'compatible' (at least for
developers) with C. I do think that once you get used to it, i8/u8 are easier on the eyes.

Since C2 will be used for the same domain of problems as C is now, UTF support is not really high on the agenda.
It's not a systems language per-se as Go and Rust.

155
General Discussion / Re: Pthreads
« on: November 24, 2015, 08:17:11 PM »
The issue mentioned in the previous post has revealed a bigger challenge. My original idea was
to support C libraries in a similar way to Rust supports external packages (with Cargo). However,
since there is such a massive fragmentation in ways of deploying C libraries, you would either
have to depend on pkg-config or something similar to extract include-paths etc from the system
or manually keep a list per platform (which is simply undoable).

The good thing is that the requirements for C2 are much different than for a language like C++.
C++ is a systems programming language and needs extensive library support and more importantly
often use libraries installed at system level. Historically libraries were all installed at system level
and so the headers were placed somewhere in /usr/include (or similar). However, there is a recent trend
in new languages to not use system-level libraries, but just to download copies locally. This exchanges
complexity for disk-space (an easy choice). The same goes for the shift from dynamic to static libraries.
Rust (with Cargo) and LLVM/Clang are examples of this new approach.

Since C2 is meant for relatively isolated programs, I think having the user have to add a library manifest
for a specific platform is not a big problem.

This part above is only about using C-libraries from C2. There will also be a thing like C2-libraries.
For the design of this, we have a chance to shed a lot of legacy and apply 30 years of learned lessons. So
which lessons have we learned...?



156
General Discussion / Pthreads
« on: November 20, 2015, 09:49:30 PM »
Now that library support is in place, I've been trying out pthreads. This is quite a weird library it seems.
On OS X, compilation doesn't need a special linker flag. If you pass '-pthread', clang gives a warning about
'unused flag'. On linux, clang needs '-pthread' to build, otherwise you get an 'undefined reference to..' warning.

Nasty..

157
Ideas / Re: Unsigned char
« on: September 18, 2015, 08:39:02 AM »
I realize that one of the missing entries in the documentation is how C2 handles constants (or literals). For example:
Code: [Select]
int8 a = 200;
int8 b = 100 + 28;
int8 c = 28 + 'a';
intc d = 28 + 'z';
In C2 the value 200 is not converted into int or long, but C2 checks if the *value* fits the LHS. This also works
works for constant expressions as 100 + 28 etc. So  assigning to c is ok ('a' = 98, so total is 126), while assigning
to d raises an error (since the total > 127). That's how it is with constants.

It's very unfortunate that you ran into the issue with the parsing of sizeof(). There are only a few of those gaps
left in the parser, but there's always Murphy's law of course...

For checking things like sizeof('a') or sizeof(char*), static asserts would be best I think.. This is not in C2 yet, but
shouldn't be that hard to implement.


158
Ideas / Re: Unsigned char
« on: September 14, 2015, 08:09:13 PM »
The problems I was expecting were assigning -1 as special value to char to indicate some special case, like:
Code: [Select]

char c = -1;
..
if (c != -1) {
   ..
} // else ignore

Changing char to unsigned would force this type of code to use some other special value (like 0) or add the burden of using a second variable to indicate valid-ness.


The parsing of X in sizeof(X) is still very limited. One issue is that at parse-time, the parser doesn't know if X is a type or a symbol.
I also wanted to keep things same and since I have never really seen sizeof('a') or sizeof(10) in any production code, wanted to remove this option. So only <type> or <symbol> would be allowed. Does this make sense?

159
Ideas / Re: Unsigned char
« on: September 11, 2015, 08:49:10 AM »
I'm currently implementing the proposed change (char == uint8). The next interesting question I
run into is the following: the following piece of code should work right?
Code: [Select]
const char* text = "Hello World";
char c = 'a';

So changing *char* would imply that the type of string literals would also change to uint8 and that a
character literal ('a') would also have the type uint8..
I don't think the impact is very big, but I'm asking here to avoid overseeing something important...

160
Implementation Details / Re: BitOffsets
« on: September 08, 2015, 09:41:10 PM »
Any embedded programmer is reading a lot of hardware specifications. In those documents, register fields are often specified in the form of [18:16]. I tried to copy this exactly into C2.

I think the syntax just takes some getting used to. The width is (high - low + 1). When reading the hardware specs, developers are used to the same thing right? My preference would be to use the high:low instead of low:width proposal, also since both value are then offsets instead of an offset and a width. Does this make sense?

What I haven't fleshed out is that code often use macros to define field offsets and widths. Is the bitterest syntax this would look like for some field called counter

Code: [Select]
uint32 value = reg[COUNTER_HIGH: COUNTER_LOW];


Ideally this would be caught into a single thing. This would require different syntax options like specifying register sub-fields or something..

161
Ideas / Re: Enum classes
« on: August 30, 2015, 11:55:47 AM »
Let's discuss the enums first. One of my goals is to make the language as unambiguous as possible.
So code like

Code: [Select]
a.b
can be 2 things:
  • 'a' a module and 'b' a symbol (type, var or function) of that module
  • 'a' a struct and 'b' a member of that struct

I sometimes find it handy to isolate enum values from a regular 'namespace', especially
if there are multiple enum types in the same 'namespace'. If we would add this feature,
using the dot operator would make things more ambiguous (like a.b.c), so therefore I
tried the :: operator. I agree that this somewhat breaks the uniformity of the syntax...

As a sidenote, so does the current 'cast' operator, but the old C-style cast simply wasn't
very parse-able..

The second issue you mention, whether a single level of module name spacing is sufficient
is indeed another matter. I think there is a different post discussing that. There we concluded that
having a single level is already better than none and that adding more would only add more
complexity without too much gain. You can of course use something like

Code: [Select]
module qemacs_foobar;

and then import it like
Code: [Select]
import qemacs_foobar as foobar;
Porting a larger project to C2 would be a *very* nice way to see how some features fit!

162
Ideas / Re: Unsigned char
« on: August 30, 2015, 11:43:05 AM »

Good arguments! Can't argue with that ;)
I'll change the char to uint8.

Currently char in equal to int8 (and will be equal to uint8), so char* and uint8* will be completely
equal then (just different syntax). Do you mean you want to make char* and uint8* incompatible
or char* and int8* ? (after changing char to unsigned)

163
Ideas / Enum classes
« on: July 20, 2015, 04:43:25 PM »
Recently C++11 introduced the concept of enum classes. This puts the enum constants
in their own enum's namespace. So:

Code: [Select]
enum class State {
   START,
   MIDDLE,
   END
};

This allows the compiler to detect clashes between different enums and some other tricks. A second advantage
is avoiding name clashes between the MIDDLE of one enum type with MIDDLE of the second enum type.

In C2 there are already modules to avoid clashes, but currently the enum constants (like START, MIDDLE, etc)
end up in that modules namespace. I'm toying with the idea to always put enum constants in their own namespace.
The declaration will still look exactly the same, but the usage now uses an enum namespace, like

Code: [Select]
module test;

type State enum int32 {
  Start,
  Middle,
  End
}

func void foo() {
   State s1 = Start;               // current situation (full: test.Start)
   State s2 = State::Start;     // option 1 (full: test.State::Start)
   State s3 = State.Start;      // option 2 (full: test.State.Start)

}

Note that the module member operator is already a dot (.). I prefer test.State::Start over
test.State.Start, since it distinguishes the enum namespace and a.b is always either a module
or struct member. Once again I look for the experience and wisdom of the forum members :)

164
Ideas / Re: one big design item: Macros
« on: May 06, 2015, 08:15:53 PM »
1) C2 has already got it's own AST, independent of Clang's. LLVM IR code is generated from that AST.
2) I'm currently looking into the include-what-you-use (iwyu) tool. With some modifications to iwyu,
I can extract definitions for functions, types and variables and convert them into C2 automatically by
walking clang's AST tree. I'm hoping to show some demo functionality this month. As always,
however, macros are hard. It is possible to find them in the AST, and the left has side (declaration
part) is usable. The right-hand side it almost useless. Only if it's a constant, would it be usable. If it's
something the code below, it's very hard to use.
Code: [Select]
#define myprint(x) if (x > 10) print_##x()
Of course we could just generate a warning on conversion and an error on use of such macros.

3) Since C2 uses clang's pre-processor, old-style macros already work. Already you can specify
the following in the recipe.txt file:
Code: [Select]
target foo
  $config FEATURE_A, FEATURE_C
  foo.c2
end
And the 2 strings are added to the preprocessor as if (#define FEATURE_A).

My first goal would be to automatically parse C headers files, ignoring the macros. This would allow
usage of stdio.h, stdlib.h, string.h, etc
The second goal would be to parse simple macros like "#define MAX_BUFFER 10".
After that we'll see..

165
General Discussion / Modules
« on: May 04, 2015, 11:41:09 AM »
The default C/C++ language communities are gaining momentum to fix the Header file problem.
Here is another interesting proposal for Modules in C++:

http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4465.pdf

What I noticed was that they also state macro's as a big problem and also use the word Evolution.
So more indications we're moving in the right direction  :D

There are some differences howevery:
  • In C2, you can choose which declarations to export outside the source (in the recipe file)
  • The paper exports all symbols put in the module, C2 distinguishes between public in a Module and exporting from the compilation unit
  • The paper proposal sub-modules, while C2 only allows a single layer to avoid having to mangle the symbols
  • In C2 you only type-once, so no forward decls, etc. The paper requires exporting the symbol, separate from defining it.

Pages: 1 ... 9 10 [11] 12 13 ... 15