Thread overview
March 24

I'm creating a library that is completely pure, but it doesn't compile with pure: at the top because of one impure unittest (which uses random to test some things only probabilistic)!

So do I really need to declare every function pure individually because of a test?!?

Can we please have a @impure attribute?
And by the way also @throws and @gc?
That would make live so much easier...

March 24
On Sunday, March 24, 2024 1:41:41 AM MDT Dom DiSc via Digitalmars-d-learn wrote:
> I'm creating a library that is completely pure, but it doesn't compile with pure: at the top because of one impure unittest (which uses random to  test some things only probabilistic)!
>
> So do I really need to declare every function pure individually because of a test?!?
>
> Can we please have a @impure attribute?
> And by the way also @throws and @gc?
> That would make live so much easier...

It's been brought up a number of times before that it would be desirable to have a way to negate attributes, and maybe we'll get that ability at some point, but for now, we don't have it. The only attributes that can be negated are @safe, @trusted, and @system, because using one of them directly on a function overrides any others that are applied more globally. So, for now, you cannot apply pure to an entire module and then have it not apply to something within the module (though you could put that one test at the top before you apply pure).

Another thing you could do would be to use debug {} to ignore attributes within that block (though then that code will only be run when building with -debug). How much sense that makes depends on what your test is doing, but it is a way to get around pure in code that isn't intended to be used in production.

All of that being said, I'd be inclined to argue that in general, mass-applying attributes is asking for trouble. It works to a point, but it makes it easy to forget which attributes apply, and in some cases, attributes get ignored when they're mass-applied (though that's mostly on types IIRC). It makes more sense when you're applying an attribute to the entire module and not just a section of a module, but it does have a tendency to become a maintenance problem - particularly when it's code that more than one person works on. It also makes code harder to review, because diffs won't include any of the attributes that are being mass-applied, making it easy to miss the fact that a particular attribute applies to the code being changed.

So, yes, you've run into a problem that it would be nice to have a better fix for, but even if we could negate attributes in general, there are good reasons to prefer to avoid mass-applying attributes.

- Jonathan M Davis



April 05
On Sunday, 24 March 2024 at 09:16:20 UTC, Jonathan M Davis wrote:
> So, yes, you've run into a problem that it would be nice to have a better fix for, but even if we could negate attributes in general, there are good reasons to prefer to avoid mass-applying attributes.

I don't see it as "mass-applying attributes" rather than changing the default to something more sane, so that I have to apply *less* attributes to any single function.

If the addition of new keywords (like "throws", "@gc" and "impure") is a problem, why not doing it like @nogc(false) or @nogc=false (likewise for nothrow and pure)?
April 06
On Friday, April 5, 2024 3:11:42 AM MDT Dom DiSc via Digitalmars-d-learn wrote:
> On Sunday, 24 March 2024 at 09:16:20 UTC, Jonathan M Davis wrote:
> > So, yes, you've run into a problem that it would be nice to have a better fix for, but even if we could negate attributes in general, there are good reasons to prefer to avoid mass-applying attributes.
>
> I don't see it as "mass-applying attributes" rather than changing the default to something more sane, so that I have to apply *less* attributes to any single function.

The core issue is that the place that is applying the attributes is far from what they're being applied to, which makes it extremely easy to miss them and not know which attributes are actually being applied - particularly when reviewing code, since then you tend to be looking primarily at diffs and not the entire file. It's going to be less of a problem with personal projects, but with any project where multiple people work on the code, it can start being a problem. Ultimately, having the attributes directly on what they apply to tends to result in fewer maintenance issues - particularly with larger projects.

> If the addition of new keywords (like "throws", "@gc" and
> "impure") is a problem, why not doing it like @nogc(false) or
> @nogc=false (likewise for nothrow and pure)?

There are a number of ways that it could be done, but regardless, we'd need a DIP and an implementation, and neither has happened. It's a known problem but hasn't been a big enough problem to have been made a priority.

- Jonathan M Davis



April 07

On Sunday, 24 March 2024 at 07:41:41 UTC, Dom DiSc wrote:

>

I'm creating a library that is completely pure, but it doesn't compile with pure: at the top because of one impure unittest (which uses random to test some things only probabilistic)!

So do I really need to declare every function pure individually because of a test?!?

Can we please have a @impure attribute?
And by the way also @throws and @gc?
That would make live so much easier...

A better way to apply a attribute to an entire file is to use an explicit scope you can still apply this to basically the entire file but leave the tests out of it.

second since these are test its better for them to be pure, so use debug as it implicitly tells you where all global mutation happen, if you need your unit tests to run without debug for what ever reason fall back to suggestion one.

dmd test.d -debug

// File name test.d
import std.stdio;

int var = 0;

void main() {
  writeln(var);
  var = 1;
  writeln(var);
  foo();
  writeln(var);
  baz();
  writeln(var);
}

pure {

  int foo() {
    debug { var = 2;}
    return 2;
  }
  // you can nest scopes
  @safe {
    int bar () {
      return 3;
    }
  }
}

void baz() {
  var = 4;
}

April 08

On Sunday, 24 March 2024 at 07:41:41 UTC, Dom DiSc wrote:

>

I'm creating a library that is completely pure, but it doesn't compile with pure: at the top because of one impure unittest (which uses random to test some things only probabilistic)!

So do I really need to declare every function pure individually because of a test?!?

Can we please have a @impure attribute?
And by the way also @throws and @gc?
That would make live so much easier...

Try debug unittest {...}?

April 08

On Sunday, 7 April 2024 at 23:32:24 UTC, MrJay wrote:

>

A better way to apply a attribute to an entire file is to use an explicit scope you can still apply this to basically the entire file but leave the tests out of it.

Better than an explicit impure (or pure=false) attribute?
I don't think so. It heavily uglyfies the file, as single items without a specific attribute are interspersed in the file. So the scope need to end before and start again after the affected function or test.

An it stops working at all if e.g. one test is impure and another test is @gc, because then the scopes overlap and can no more be contained in each other.

Really, having the counter-attributes would improve the language.

April 08

On Monday, 8 April 2024 at 07:03:40 UTC, Alexandru Ermicioi wrote:

>

On Sunday, 24 March 2024 at 07:41:41 UTC, Dom DiSc wrote:

>

I'm creating a library that is completely pure, but it doesn't compile with pure: at the top because of one impure unittest (which uses random to test some things only probabilistic)!

So do I really need to declare every function pure individually because of a test?!?

Can we please have a @impure attribute?
And by the way also @throws and @gc?
That would make live so much easier...

Try debug unittest {...}?

Cool. This seems to work. That's a nice workaroud for tests. Yay!

April 08

On Monday, 8 April 2024 at 07:53:01 UTC, Dom DiSc wrote:

> >

On Sunday, 24 March 2024 at 07:41:41 UTC, Dom DiSc wrote:
Try debug unittest {...}?

Cool. This seems to work. That's a nice workaroud for tests. Yay!

Nice, fyi, you can use it with statements inside function bodies as well. Usefull for doing logging in pure functions.