Jump to page: 1 210  
Page
Thread overview
Code That Says Exactly What It Means
6 days ago
Peter C
6 days ago
monkyyy
6 days ago
Peter C
6 days ago
monkyyy
6 days ago
Peter C
4 days ago
Walter Bright
6 days ago
Kapendev
5 days ago
Peter C
5 days ago
Peter C
5 days ago
Serg Gini
5 days ago
Peter C
4 days ago
Walter Bright
4 days ago
monkyyy
4 days ago
Kapendev
4 days ago
Peter C
4 days ago
Walter Bright
4 days ago
Peter C
4 days ago
Lance Bachmeier
3 days ago
Peter C
3 days ago
monkyyy
3 days ago
Kapendev
3 days ago
claptrap
3 days ago
Lance Bachmeier
3 days ago
Peter C
3 days ago
claptrap
3 days ago
Serg Gini
3 days ago
Kapendev
3 days ago
claptrap
2 days ago
Kagamin
3 days ago
Peter C
3 days ago
jmh530
3 days ago
Paul Backus
3 days ago
jmh530
3 days ago
Sergey
3 days ago
H. S. Teoh
2 days ago
jmh530
2 days ago
Peter C
2 days ago
Peter C
2 days ago
Peter C
2 days ago
zod
2 days ago
Kapendev
2 days ago
Peter C
2 days ago
Peter C
2 days ago
Zealot
2 days ago
Peter C
2 days ago
ealot
1 day ago
Peter C
2 days ago
Kagamin
2 days ago
Kagamin
2 days ago
Sergey
1 day ago
claptrap
2 days ago
Dom DiSc
2 days ago
jmh530
2 days ago
H. S. Teoh
2 days ago
Kagamin
1 day ago
Walter Bright
1 day ago
Walter Bright
1 day ago
Peter C
2 days ago
Peter C
3 days ago
Peter C
2 days ago
Zealot
2 days ago
Arafel
2 days ago
Zealot
2 days ago
Lance Bachmeier
2 days ago
Kapendev
2 days ago
Kagamin
3 days ago
zod
4 days ago
jmh530
4 days ago
Max Samukha
4 days ago
jmh530
4 days ago
Peter C
3 days ago
Peter C
4 days ago
jmh530
4 days ago
Walter Bright
4 days ago
Peter C
4 days ago
Sergey
4 days ago
Kapendev
4 days ago
Walter Bright
4 days ago
Walter Bright
4 days ago
Peter C
3 days ago
Kapendev
3 days ago
Paul Backus
3 days ago
Abdulhaq
3 days ago
Serg Gini
4 days ago
Kapendev
6 days ago
Among D developers, the idea of adding a new visibility attribute like scopeprivate often meets with scepticism. After all, D already has private for module-level encapsulation and package for sharing across sibling modules. And if you really want to lock a class down, you can always put it in its own module. So why bother?

The problem is that these existing tools force you into coarse choices. If helpers and tests live in the same module, they see everything. If you isolate the class in its own module, they see nothing. And while package is useful for widening access across a package hierarchy, it doesn't let you narrow visibility inside a module. Rather, package widens visibility, across a whole package hierarchy. That's not the same as narrowing it down. In practice, this means you can't express a very common design intent: "helpers in the same module should see some internals, but not the most sensitive ones."

That's where a 'scopeprivate' comes in. It introduces a missing rung on the visibility ladder: type-only access. With it, you could mark fields like Account.id or Account.owner as private or package, so persistence and logging helpers can use them, while marking fields like Account.balance or Account.authToken as scopeprivate, so only the class itself can touch them. The compiler enforces this boundary, preventing accidental leaks in logs, persistence, or tests. You no longer need to split every class into its own module just to achieve stricter encapsulation, and you no longer need to rely on convention or code review to stop sensitive data from slipping out.

In other words, scopeprivate doesn't make the impossible possible - you can already hack around with module boundaries and package. What it does is make disciplined program design, explicit and enforceable. It lets you express intent directly at the declaration site, keeps related code together without sacrificing safety, and ensures that invariants remain protected by construction.

For developers who care about clarity, maintainability, and correctness, that's not redundant - it's a meaningful step toward code that says exactly what it means.

module exampleOnly;
@safe:
private:

//import std;
import std.stdio : writeln;
import std.exception : enforce;

public class Account
{
  private
  {
      int id;
      string owner;
  }

  scopeprivate
  {
      double balance;
      string authToken;
  }

  public this(int id, string owner, double openingBalance, string token)
  {
      this.id = id;
      this.owner = owner;
      this.balance = openingBalance;
      this.authToken = token;
  }

  public void deposit(double amount)
  {
      enforce(amount > 0, "Deposit must be positive");
      balance += amount;
  }

  public void withdraw(double amount)
  {
      enforce(amount > 0 && amount <= balance, "Invalid withdrawal");
      balance -= amount;
  }

  public double getBalance() const { return balance; }
}

// Can see IDs and owners (enough to write to DB), but not balances or tokens.
public void saveToDatabase(Account a)
{
  writeln("[DB] INSERT INTO accounts (id, owner) VALUES (", a.id, ", '", a.owner, "')");

  // Example compiler message if you were to uncomment the lines below:
  // writeln("Balance: %s", a.balance);
  // Error: no property `balance` for `a` of type `finance.Account` [`balance` is not accessible here]

  // writeln("AuthToken: %s", a.authToken);
  // Error: no property `authToken` for `a` of type `finance.Account` [`authToken` is not accessible here]
}

// Logs can include IDs and owners for traceability, but cannot leak sensitive state.
public void logTransactionStart(Account a, string action)
{
  writeln("[LOG] Account id=", a.id, " owner=", a.owner, " starting action=", action);

  // Example compiler message if you were to uncomment the lines below:
  //writeln("[LOG] Account balance = %s", a.balance);
  // Error: no property `balance` for `a` of type `finance.Account` [`balance` is not accessible here]

  //writeln("[LOG] Account authToken = %s", a.authToken);
  // Error: no property `authToken` for `a` of type `finance.Account` [`authToken` is not accessible here]
}

public void logTransactionEnd(Account a, string action, bool success)
{
  writeln("[LOG] Account id=", a.id, " owner=", a.owner, " finished action=", action, " status=", success ? "OK" : "FAILED");
}

// Unit tests are also subject to scopeprivate's visibility restriction.

// Compile-time visibility tests
unittest
{
  auto acc = new Account(5, "Eve", 400.0, "tok5");

  // Allowed:
  static assert(__traits(compiles, acc.getBalance()));

  // Forbidden (scopeprivate):
  static assert(!__traits(compiles, acc.balance));
  static assert(!__traits(compiles, acc.authToken));
}

// Constructor tests
unittest
{
  auto acc = new Account(1, "Alice", 100.0, "tok");
  assert(acc.getBalance() == 100.0);
}

// Deposit tests
unittest
{
  import std.exception : assertThrown;

  auto acc = new Account(2, "Bob", 50.0, "tok2");
  acc.deposit(25.0);
  assert(acc.getBalance() == 75.0);

  assertThrown!Exception(acc.deposit(0));
  assertThrown!Exception(acc.deposit(-10));
}

// Withdraw tests
unittest
{
  import std.exception : assertThrown;

  auto acc = new Account(3, "Charlie", 200.0, "tok3");
  acc.withdraw(50.0);
  assert(acc.getBalance() == 150.0);

  assertThrown!Exception(acc.withdraw(0));
  assertThrown!Exception(acc.withdraw(-5));
  assertThrown!Exception(acc.withdraw(500)); // too much
}

// Logging and DB output tests
@system unittest
{
  // helper to capture writeln output
  string captureOutput(void delegate() dg)
  {
      import std.array : appender;
      import std.stdio : stdout, File;
      import core.stdc.stdio : fflush;
      import std.string : strip;

      auto buf = appender!string();
      auto old = stdout;
      auto f = File.tmpfile();
      scope(exit) f.close();

      stdout = f;
      dg();
      fflush(f.getFP());

      f.rewind();
      foreach (line; f.byLine)
         buf.put(line.idup);

      stdout = old;
      return buf.data.strip;
  }

  auto acc = new Account(4, "Dana", 300.0, "tok4");

  auto dbOut = captureOutput({ saveToDatabase(acc); });
  assert(dbOut == "[DB] INSERT INTO accounts (id, owner) VALUES (4, 'Dana')");

  auto logStart = captureOutput({ logTransactionStart(acc, "deposit"); });
  assert(logStart == "[LOG] Account id=4 owner=Dana starting action=deposit");

  auto logEndOk = captureOutput({ logTransactionEnd(acc, "deposit", true); });
  assert(logEndOk == "[LOG] Account id=4 owner=Dana finished action=deposit status=OK");

  auto logEndFail = captureOutput({ logTransactionEnd(acc, "withdraw", false); });
  assert(logEndFail == "[LOG] Account id=4 owner=Dana finished action=withdraw status=FAILED");
}

6 days ago
On Sunday, 26 October 2025 at 06:33:11 UTC, Peter C wrote:
> Among D developers, the idea of adding a new visibility attribute like scopeprivate often meets with scepticism.
>
> For developers who care about clarity, maintainability, and correctness, that's not redundant - it's a meaningful step toward code that says exactly what it means.

"What do you call a specification that a computer can turn into a program? code we call it code"; this cuts both ways, both telling "business logic"/vibe coders to go to hell; and you to shut up if my code compiles.

If you take 300 lines to implement what I can in 10, your *just factually* being verbose and redundant, mere assertions otherwise are absurd. I hate function coloring, I hate "stop working" tagging, I hate extending dependencys... I hate safetyism itself.

> code

You wrote a big class, only to use floats to represent money. All the safety keywords and you broke your type theory. When you do this, youd be fired instantly; but if for some reason you managed to ship people would steal pennies with floating point errors.

Your reducing clarity.
6 days ago
On Sunday, 26 October 2025 at 08:32:37 UTC, monkyyy wrote:
>
> ..
> You wrote a big class, only to use floats to represent money. All the safety keywords and you broke your type theory. When you do this, youd be fired instantly; but if for some reason you managed to ship people would steal pennies with floating point errors.
>
> Your reducing clarity.

You might be missing the point here ;-)

Of course my background is in C#, where I (regulary) use a decimal type. But my knowledge of D is somewhat limited - I don't think it even has a decimal type?? - and the code was merely an example (as per the name of the module) to demonstrate code that desires to narrow the visiblity,in a particular case, not widen it (with package). Nothing else in the code is relevant here, except 'how' to implement that programmers desire.

In that example code, it is 'scopeprivate' that allowed the programmer of that code, to do just that, in an explicit and enforceable manner.

Without scopeprivate, I'm not sure how that programmer could have expressed that intent 'in a meaningful way', and certainly not in a way that is enforceable.

6 days ago

On Sunday, 26 October 2025 at 06:33:11 UTC, Peter C wrote:

>

scopeprivate

Don't have a strong opinion about this because I'm not the target user. The only time I use private is when I have something temporary in my library or some internal C bindings. I can see it being useful I guess for some people. The simplest solution now is to prefix your "scopeprivate" functions with a _. Ugly names are kinda powerful because you always feel weird about using them. Same as __traits or __gshared I assume :)
You can also search for _ in your source code. Not the solution you want probably, but anyway.

6 days ago

On Sunday, 26 October 2025 at 06:33:11 UTC, Peter C wrote:

>

Among D developers, the idea of adding a new visibility attribute like scopeprivate often meets with scepticism. After all, D already has private for module-level encapsulation and package for sharing across sibling modules. And if you really want to lock a class down, you can always put it in its own module. So why bother?

[...]

This has been proposed and rejected many times. In D private is for the module. This is intentional.

-Steve

6 days ago
On Sunday, 26 October 2025 at 09:35:47 UTC, Peter C wrote:
> But my knowledge of D is somewhat limited - I don't think it even has a decimal type??

the core devs just hate datastructures, fixed point type would be reasonable to ask from an std and probably would be 50 lines of code ish

But that should be a lib type not a fundamental one

> scopeprivate

I believe its in opend but feel free to guess how much I verified it works
6 days ago
On 27/10/2025 4:51 AM, monkyyy wrote:
> On Sunday, 26 October 2025 at 09:35:47 UTC, Peter C wrote:
> 
>     But my knowledge of D is somewhat limited - I don't think it even
>     has a decimal type??
> 
> the core devs just hate datastructures, fixed point type would be reasonable to ask from an std and probably would be 50 lines of code ish
> 
> But that should be a lib type not a fundamental one

It is a LOT more than 50 lines.

- Somebody who has actually written a fixed point data type.
6 days ago
On Sunday, 26 October 2025 at 15:51:51 UTC, monkyyy wrote:
> On Sunday, 26 October 2025 at 09:35:47 UTC, Peter C wrote:
>> But my knowledge of D is somewhat limited - I don't think it even has a decimal type??
>
> the core devs just hate datastructures, fixed point type would be reasonable to ask from an std and probably would be 50 lines of code ish
>
> But that should be a lib type not a fundamental one
>
>> scopeprivate
>
> I believe its in opend but feel free to guess how much I verified it works

opend is where I got the idea. (though I got uncomfortable with typing (and looking at) 'private(this)' and changed it to 'scopeprivate'.

It works well enough in opend, but the implementation needs a little more work. Just for example, in D, all non-static, non-final member functions of a class are virtual unless they are private or package functions. So private(this) member functions should not be virtual. This is a pretty simple fix in fund.d
5 days ago

On Sunday, 26 October 2025 at 14:55:07 UTC, Steven Schveighoffer wrote:

>

On Sunday, 26 October 2025 at 06:33:11 UTC, Peter C wrote:

>

Among D developers, the idea of adding a new visibility attribute like scopeprivate often meets with scepticism. After all, D already has private for module-level encapsulation and package for sharing across sibling modules. And if you really want to lock a class down, you can always put it in its own module. So why bother?

[...]

This has been proposed and rejected many times. In D private is for the module. This is intentional.

-Steve

I'm wouldn't say I'm proposing it, but rather demonstrating how it would be useful.

D's philosophy that modules are the true encapsulation boundary, is just that, a philosophy.

The code I presented, and the reasoning behind it, is the real world, and that is what matters.

I do agree that the module boundary makes complete sense when you're dong Rust like programming. But when you are programming with objects, based on class types - and come from one of the many languages that do support a boundary on the class type - and discover that in D the class type has no boundary, the mental model of OOP becomes blurred. I believe when Swift became widely used, there was some significant pushback on how they blurred the boundaries on types. I would expect the same to occur in D, if it ever achieved wide spread use.

Imagine you're looking for a new building for your business, and you ask the proprietor whether i can put locks on some of the offices, and the proprietor says, no you cannot. If you want a locked office, you'll need to put it in a separate building.

5 days ago

On Sunday, 26 October 2025 at 14:55:07 UTC, Steven Schveighoffer wrote:

>

This has been proposed and rejected many times. In D private is for the module. This is intentional.

-Steve

btw. just for interest sake if nothing else... Swift's 'privacy saga' is a neat case study in how language design collides with developer expectations.

In the end, developers mental model of 'classes as encapsulation units' was too entrenched for the Swift design team to ignore.

Mental models can be really hard to change.

https://swiftunwrapped.github.io/episodes/4e7ad642/

« First   ‹ Prev
1 2 3 4 5 6 7 8 9 10