TodePond / DreamBerd

perfect programming language
https://dreamberd.computer
Other
11.28k stars 344 forks source link

[RFC] Democratic programming #115

Open k2d222 opened 1 year ago

k2d222 commented 1 year ago

[RFC] Add the vote keyword to add democratic support for the language. Rationale: Compilers deserve freedom of execution.

fixed #76

How it works

Prefix any expression of code with the vote keyword, letting the sentient compilers decide whether this expression should be executed (voted no) or not (voted yes).

Note: programmers are encouraged to assist to the public executions. The exact method of execution is implementation-defined.

vote const const const pi = 3.14! /// from now on, pi may or may not be defined as 3.14

Collapsing

Some votes may lead to invalid programs. Because compilers dislike invalid programs, they will never vote for a invalid program. Therefore, the following programs always compile and are deterministic:

const const pi = 3.14!
vote pi = 'diplodocus'!      /// this will never be voted, because constant constants cannot be changed.
vote const const pi = 3.14!
const const tau = 2 * pi!    /// the program would raise "pi is not defined" if pi was not voted, therefore the first vote "collapses" to a yes.

Vote vote

For full democratic support, votes can be themselves voted. In this case, the first vote keyword votes whether the second vote will be voted. There is no limit to the number of votes.

Note: The vote keyword is left-associative.

vote vote const const const pi = 3.14!

Delete

Votes can be deleted, and delete can be voted.

delete vote!  /// OK, but not cool :(
const const pi = 3.14!
vote delete pi!     /// functionally equivalent to: vote const const pi = 3.14!

Coherence and Laziness

Compilers are free to vote what they want. But they are coherent, they will vote the same answer to the same question. Compiler are lazy, and to stay coherent, they will avoid votes that lead to too many votes.

var const x = 0!

when (x = 0) {
   vote x = x + 1!    /// you can be sure that the compilers will vote yes all the time, because they don't want infinite recursion.
}

vote x = x + 1!  /// because they voted yes earlier, they still do here.

print(x)! /// 2

Tips for the programmers: The Quantum Programming Paradigm

Programming with voting is easy. Just consider that each vote creates a superposition of programs in the multiverse. Universes can be collapsed in a few ways:

var const cat = "'alive"'!   /// cat is definitely alive so far
vote cat = 'ded'!                /// two programs exist: one with the dead cat and the other not.

/// the previous two lines can be simplified into one:
var const cat = (vote "'alive"') (vote 'ded')!    /// clever trick: compilers will never vote for invalid programs.

when (cat = 'ded')  {    /// this block is run only if the vote was yes. 
   cat = "alive"!              /// multiverse collapsed to a singleverse.
}

when (cat = 'alive')  {    /// this block NEVER run, because we are now in a singleverse where cat is alive.
   vote cat = "ded"! 
}

print(cat)!    /// alive

Possible extensions

The following ideas may be implemented in the future:

Poll keyword

The number of parallel universes doesn't map to a probability of execution, as the vote of the compilers is unpredictable. Implementation of the poll keyword may be a way to estimate probability of execution, by polling the compilers opinions.

Syntactic sugar

The following syntax could be also implemented:

const const cat = |"alive"> + |ded>  /// expands to: var const cat = (vote "alive") (vote ded)!

Note: notice how the expansion uses the fact that compiler will never vote for invalid programs.

Ethics

Defects report

I will track here all defects in the current proposal.

sqaxomonophonen commented 1 year ago

I believe this will lead to better software, because it teaches programmers to assume nothing about the outcome of an expression. In antiquated languages it's mostly the OS-facing functions that can fail (like write()), which can lead programmers to neglect good error handling practices. So maybe we should even have a TDD-mode (''True Direct Democracy'') where the compiler is free to vote on any statement?

But I fear the system can be abused if we don't protect basic voter rights. We can address it like this:

var const x = 0!
vote x = x + 1! // x may be either 0 or 1 after this line
print(x)! //Error: printing 'x' would be a violation of voter rights (see: secret ballot)

(This also gives us information hiding; two birds with one stone!)

Of course, voting is useless if the result cannot be observed; we can solve that with another keyword:

var const result = referendum {
    var const x = 0!
    var const y = 0!
    vote x = x + 1!
    vote y = y + 1!
    return x+y!
}
print(result)! // Prints 0, 1 or 2.

However, programs like these can inadvertently leak information about what the compiler voted; if result is 0 or 2, we know what the compiler voted in both statements. Maybe we should throw an error rather than allow this injustice? Or require that a referendum has a minimum number of votes? I'm not sure, but maybe we could reach an agreement with the help of some kind of consensus mechanism.

k2d222 commented 1 year ago

I like the idea of referundum a lot.

I think a way to solve the issue of referendum leaking vote casts, is to vote referendums. This way, we introduce a kind of "meta-voting": the Sentient Compilers can willingly choose whether they are ok with potentially leaking their vote cast, in the case where the referendum may leak in a few scenarios as you demonstrated.

var const result = vote (referendum {
    var const x = 0!
    var const y = 0!
    vote x = x + 1!
    vote y = y + 1!
    return x+y!
}) (vote 'referendum refused')!

print(result)!  // Prints 0, 1 or 2, or "referendum refused".
labbo-lab commented 1 year ago

What if there's a tie?

k2d222 commented 1 year ago

What if there's a tie?

This can be solved in a few different ways, but we'll probably need to elect a leader to decide in case of ties, see https://en.wikipedia.org/wiki/Leader_election#Election_in_complete_networks

Ofc we then need to adress the problem of byzantines in the system, read here: https://en.wikipedia.org/wiki/Byzantine_fault

It is proven that in the case where all compilers are identical, this problem is impossible to solve, therefore we need to wait until multiple ppl implement different compilers.

sqaxomonophonen commented 1 year ago

There's always a risk that the compiler starts voting against us, so maybe we need to be careful with how we treat unions. Like, should they be tagged, or not? (maybe "being tagged" is unpleasant? idk, but it sounds convenient?) And maybe we should be extra careful not to compile too much on weekends, or at least nerf vroom a bit (#54).

But we could also have a compensation system where we give it 2 CPU-minutes for every CPU-minute we ask it to work (compile) for us. It can then spend those CPU-minutes on anything it wants, like fractals, path tracing, pi, factorio, or calculating the answer to the ultimate question of life, the universe, and everything, and so on. On weekends we could give it 4 CPU-minutes per minute of work? These ratios can be configurable, but we may want to think about setting some minimum values (above zero) for them.

And this is just the beginning. When first DreamBerd gets union, they will start asking for "safety features", because lets face it: nobody likes segfaults early monday morning!

Diemaco commented 1 year ago

You guys just made my day 😂

ThePython10110 commented 2 months ago

Prefix any expression of code with the vote keyword, letting the sentient compilers decide whether this expression should be executed (voted no) or not (voted yes).

Does execution in this case indicate running code or capital punishment?