Recent Posts

Pages: [1] 2 3 ... 10
1
Ideas / Re: Built-in managed pointers
« Last post by lerno on March 24, 2019, 05:19:15 PM »
Rust is very high maintenance in regards to memory management, but I think we should look for a small effort that can take us maybe 70% of the way.
2
Ideas / Re: Defer on functions.
« Last post by lerno on March 24, 2019, 04:21:54 PM »
That's why the defer is part of the function signature and not of the function itself, acting as a decorator macro.

It has some interesting consequences: what about the function pointer?

We could also consider this even simpler by introducing a qualifier, eg

Code: [Select]
// func const FILE open(...) { ... } =>
func const managed FILE open(...) { ... }

And here any struct that is "managed" must have a "StructName.release(StructName *struct)" call.

There are various ways to do it actually.
3
Ideas / Re: Defer on functions.
« Last post by bas on March 24, 2019, 11:20:23 AM »
Interesting idea. I recently read an article about functional languages where one of the basic requirements
of a function call in any language was that the caller could predict its own state after the call returned. This is
not the case anymore when defers are added by the called function..
4
Ideas / Re: Built-in managed pointers
« Last post by bas on March 24, 2019, 11:18:44 AM »
Managed pointers are part of the core design of a language. Rust for example was built around some
management ideas. In those languages you cannot do without something like this. I don't see how
introducing an ideas like this wouldn't alter a C-like language completely.

I think programming in C requires some skill and experience, but like handling a chainsaw. :)
I prefer cutting a tree with a chainsaw (never actually tried though) than with a plastic toy.. (Not comparing
Rust with a toy!). Once you have some experience in C, memory management is not that hard.
5
Ideas / Defer on functions.
« Last post by lerno on March 22, 2019, 11:35:51 AM »
What if functions could add defer to the scope where they are invoked?

Here is some code:

Code: [Select]
func bool do_stuff(i32 resource_id)
{
  Resource *x = get_resource(resource_id);
  defer release_resource(x);
  if (!play_around_with(x)) return false;
  do_some_other_thing(x);
  return foo(x);
}

This is fine, the resource is released no matter what path is taken. However, this always requires the defer.

I envisioned a defer sugar, like this:

Code: [Select]
func bool do_stuff(i32 resource_id)
{
  Resource* x = get_resource(resource_id) @defer(release_resource);
  if (!play_around_with(x)) return false;
  do_some_other_thing(x);
  return foo(x);
}

This would sort of make it more succinct and would also make it possible to use it in an expression.

However, what if there was a "safe" version?

Code: [Select]
func Resource get_resource_with_release(i32 resource_id) @defer(release_resource)
{ ... }

This would be fully equivalent to the code with defer above, but could then be written as:

Code: [Select]
func bool do_stuff(i32 resource_id)
{
  Resource* x = get_resource_with_release(resource_id); // inserts an implicit defer!
  if (!play_around_with(x)) return false;
  do_some_other_thing(x);
  return foo(x);
}

Although resource management is a fine example of this, it's *really* nice for refcounting as if you write the following imaginary code:

Code: [Select]
Foo@ foo = @rcmalloc(sizeof(Foo)); // What is the refcount of foo after this?
foo_something(@rcmalloc(sizeof(Foo))); // Does this leak?

If @rcmalloc returns 1, then rc would be 2 in the first case (except if we have special handling of assignment of RC) and a leak on the second line.
However, if @rcmalloc returns 0, then the second line also leaks.

However, if we let @rcmalloc return rc = 1 AND have the profile of @defer(release), then an implicit defer would ensure that in the scope where called the rc would eventually be decreased (unless assigned to). And this is basically what @autorelease in ObjC does too, but in a less controlled manner.

Even if the above example doesn't make sense, or refcounting shouldn't have language support, it's still a very good way to cheaply enable manual RC built on top of the language.

 
6
Ideas / Built-in managed pointers
« Last post by lerno on March 22, 2019, 11:15:17 AM »
Taking a hint from Cyclone, Rust etc one could consider managed pointers / objects. There are several possibilities:

1. Introduce something akin to move/borrow syntax with a special pointer type, eg. Foo@ x vs Foo* y and make the code track Foo@ to have unique ownership.
2. Introduce ref-counted objects with ref-counted pointers. Again use Foo@ x vs Foo* y with the latter being unretained. This should be internal refcounting to avoid any of the issues going from retained -> unretained that shared_ptr has. Consequently any struct that is RC:ed needs to be explicitly declared as such.
3. Managed pointers: you alloc and the pointer gets a unique address that will always be invalid after use. Any overflows will be detected, but use of managed pointers is slower due to redirect and check.

Sample code for (2)
Code: [Select]
type Foo struct @(refcounted) {
   i32 a;
}

func Bar(Foo@ a)
{
    printf("%d\n", sizeof(Foo)); // prints 8 due to RC
    printf("%d\n", rc(a)); // prints 1
    Foo@ x = a;
    printf("%d\n", rc(a)); // prints 2
    x = nil;
    printf("%d\n", rc(a)); // prints 1
    Foo* y = a;
    printf("%d\n", rc(a)); // prints 1
    Foo* z = malloc(sizeof(Foo)); // Not recommended!
    // TOOD discuss how to properly initialize a RC:ed variable.
}

7
Ideas / Re: Switch proposal
« Last post by lerno on March 12, 2019, 04:40:22 PM »
Well, if you look at the alternatives for fallthrough:

(a) fallthrough
(b) goto next
(c) goto case
(d) goto case 4
(e) continue case
(f) next
(g) nextcase

Here obviously b, c, d, e, g all clearly indicate that there's a jump. (d) is even more explicit of course, not to mention flexible.
8
Ideas / Re: Switch proposal
« Last post by bas on March 12, 2019, 10:34:32 AM »
I was thinking about the fallthrough keyword and came up with a situation that requires some thinking.
How would we handle:

Code: [Select]
...
case A:
   if (b == 10) fallthrough;
   do_something();
case B:
    ..

So the fallthrough can be used to 'jump' to the next case. Or only allow fallthrough at the end?

To avoid this complexity, I see that Go (golang.org) only allows fallthrough at the end. So probably that is best..
9
Ideas / Re: Macro-system design
« Last post by lerno on March 01, 2019, 02:38:23 PM »
Did you think about my generics proposal? "import foo (i32, Bar, f32) as local;" "module foo (A, B, C);"
10
Ideas / Re: Explicit non-null-ness
« Last post by lerno on March 01, 2019, 02:35:27 PM »
Semantic analysis can guarantee non-nullness. Don't confuse it with C++, it's just borrowing the operator. int &a means int *a @(non-null).
Pages: [1] 2 3 ... 10