Re: enum functions

2023-01-11 Thread Ali Çehreli via Digitalmars-d-learn

 TLDR 

Eponymous templates that define a function pointer does not transfer the 
function call parameter to the enclosing template for type deduction. 
(Note: The term "deduction" is used with template parameters, not 
"inference".)


Also note that I am replacing 'enum' with 'auto' below to show this is 
not related to 'enum' vs 'auto'.


template foo (T) {
auto foo = (T i) => i >> 1;
}

void main() {
foo(42); // <-- Compilation ERROR
}

Error: none of the overloads of template `deneme.foo` are callable using 
argument types `!()(int)`

   Candidate is: `foo(T)`

I am not sure whether this limitation is a bug.

 TLDR 

On 1/11/23 10:01, Salih Dincer wrote:

> void main()
> {
>  enum foo : char { a = 'H', b = 'i' }

That defines two values: foo.a is 'H' and foo.b is 'i'.

>  enum bar() { return new foo; }

That is a function that returns a dynamically allocated foo value. Since 
'new' makes pointers for value types like int and enum, I think the 
return type of 'bar' is foo*.


And that pointer is pointing at a foo.init, which happens to be the 
first value defined: 'H'.


>
>  import std.stdio;
>  foreach(char f; [bar.a, bar.b])

'bar' is a function call that returned a pointer. Hm. Finally I see what 
you are talking about.


Normally, one might have written (*bar) to get the value. Let's try by 
using the following array:


  [(*bar), (*bar)]

Ok, it's what I expect:

HH

Now the interesting part is what does (*bar).a and (*bar).b mean? Let's try:

  [(*bar).a, (*bar).b]

Ok, it gives

Hi

The interesting thing is, foo.a does not print 'H' but 'a':

writeln(foo.a);
writeln(foo.b);

a
b

Ah! Finally I see your explicit 'char' in the foreach loop. That is what 
makes your code print 'H' and 'i'. :)


>  f.write;
>
>  writeln; // Hi
> }

I've just learned something: You can reach different enum values 
directly from an value itself:


import std;

void main()
{
// A type:
enum foo : char { a = 'H', b = 'i' }

// A variable:
enum x = foo.a;

// Really?
writeln(x.b);
}

Ok, it kind of makes sense but I would have written the following e.g. 
in template code. (?)


writeln(typeof(x).b);

> I think this use of enums should be prohibited. So, can I get an answer
> about not being able to make a type inference? So I'm very curious about
> the second part of the my post.

Before looking at your example, here is what I tested. The code proves 
that type inference is the same for 'auto' and 'enum' functions:


auto foo(T)(T t) {
return t;
}

enum bar(T)(T t) {
return t;
}

struct S {}

import std.meta;

void main() {
alias functions = AliasSeq!(foo, bar);
alias types = AliasSeq!(int, double, S, string, const(float));

static foreach (type; types) {
pragma(msg, "Testing ", type);
static foreach (func; functions) {
static assert (is (typeof(func(type.init)) == type));
}
}
}

It uses two function templates and a few types and as expected, the 
return types of the functions are the same.


Ok, back to your code:

> template foo (T) {
> enum foo = (T i) => i >> 1;
> }

That local 'foo' is a literal value of an anonymous function. (The local 
'foo' is not a template.) Reminding myself: Literals are rvalues and 
they are not variables. For example, they don't have addresses.


> template bar (T) {
> auto bar (T i) => i >> 1;
> }

That's different: There was an equals sign after 'foo' but not here. So 
your example is different from e.g. the following two definitions:


auto x() {}
enum y() {}

If you are curious about this case, as Adam said, there is no difference 
between 'auto' and 'enum'.
But again, your code has that extra '=' character for 'foo' and that 
makes a difference.


Getting back to 'bar', so that local 'bar' is a function definition. 
Now, calling bar from the outside as bar(42) is the same as writing 
bar!int.bar(42). (This is the eponymous template convenience.)


> import std;

> void main()
> {
> assert(oneHalf(42) == 21);
> 42.foo!int.writeln; // no inference: "21"

Your "no inference" comment was confusing me. Now I see that you meant 
that you can't write the following:


  42.foo.writeln; // <-- Compilation ERROR

Although you can write the following:

> 42.bar.writeln; // "21"
> }

Ok, let's look at the problem with the understanding of 'foo' being a 
literal. Yes, I can demonstrate the issue that mix it with the concept 
of type inference:


import std;

void main() {
enum foo = {   // Note '='
writeln("foo");
};

auto bar() {
writeln("bar");
}

foo;  // <-- Compilation ERROR
bar;
}

foo line has a compilation error:

Error: `__lambda1` has 

Re: enum functions

2023-01-11 Thread Salih Dincer via Digitalmars-d-learn

On Tuesday, 10 January 2023 at 12:55:34 UTC, Adam D Ruppe wrote:
It means nothing. The keyword tells the parser a function is 
about to begin, which triggers return type inference (exactly 
the same as `auto`), but otherwise it is completely ignored.


Sorry to give compelling examples but it can be pretty confusing 
if it comes across as if by mistake, am I wrong?


```d
void main()
{
    enum foo : char { a = 'H', b = 'i' }
    enum bar() { return new foo; }

import std.stdio;
    foreach(char f; [bar.a, bar.b])
f.write;

    writeln; // Hi
}
```
I think this use of enums should be prohibited. So, can I get an 
answer about not being able to make a type inference? So I'm very 
curious about the second part of the my post.


Thanks...

SDN@79



Re: enum functions

2023-01-11 Thread Steven Schveighoffer via Digitalmars-d-learn

On 1/10/23 7:55 AM, Adam D Ruppe wrote:

On Sunday, 8 January 2023 at 18:42:58 UTC, Salih Dincer wrote:
I'm wondering 2 things; firstly, does having an enum mean there is no 
auto-return? Or could it be CTFE?


It means nothing. The keyword tells the parser a function is about to 
begin, which triggers return type inference (exactly the same as 
`auto`), but otherwise it is completely ignored.


Mostly correct. `enum` is a storage class, which means a *declaration* 
is about to begin. Once the declaration is decided as a function 
definition, type inference is performed, and the storage class is 
checked to see how it affects the declaration. In some cases, there is 
an effect, in some there is not.


```d
static foo() {} // static does nothing here
final bar() {} // final does nothing here
enum baz() {} // enum does nothing here
__gshared fun() {} // __gshared does nothing here

struct S
{
   // return type is int *, `this` (unused) is const
   const foo() { return new int; }
   // same for immutable, shared, inout
}
```

Aside from the const/immutable/shared/inout storage classes (which do 
affect semantics, but maybe in slightly confusing ways) there are some 
which are pretty obvious and also work with type inference:


1. deprecated
2. extern
3. abstract
4. override
5. synchronized
6. auto
7. scope
8. nothrow
9. pure
10. ref

-Steve


Re: enum functions

2023-01-11 Thread bauss via Digitalmars-d-learn

On Tuesday, 10 January 2023 at 12:55:34 UTC, Adam D Ruppe wrote:

On Sunday, 8 January 2023 at 18:42:58 UTC, Salih Dincer wrote:
I'm wondering 2 things; firstly, does having an enum mean 
there is no auto-return? Or could it be CTFE?


It means nothing. The keyword tells the parser a function is 
about to begin, which triggers return type inference (exactly 
the same as `auto`), but otherwise it is completely ignored.


I'm curious about why it is allowed and whether we somehow could 
use it for something meaningful since it really just is an alias 
for auto right now.


Perhaps it could be used to create functions that only live at 
compile-time.


Re: enum functions

2023-01-10 Thread Adam D Ruppe via Digitalmars-d-learn

On Sunday, 8 January 2023 at 18:42:58 UTC, Salih Dincer wrote:
I'm wondering 2 things; firstly, does having an enum mean there 
is no auto-return? Or could it be CTFE?


It means nothing. The keyword tells the parser a function is 
about to begin, which triggers return type inference (exactly the 
same as `auto`), but otherwise it is completely ignored.


Re: enum functions

2023-01-09 Thread Salih Dincer via Digitalmars-d-learn

On Sunday, 8 January 2023 at 18:42:58 UTC, Salih Dincer wrote:


I'm wondering 2 things; firstly, does having an enum mean there 
is no auto-return? Or could it be CTFE?


Second, why is there no inference when I use an enum in one of 
the functions below?


I'm still wondering 

SDB@79


Re: enum functions

2023-01-08 Thread Salih Dincer via Digitalmars-d-learn

On Sunday, 8 January 2023 at 18:42:58 UTC, Salih Dincer wrote:

I accidentally had a function like this:

```d
enum oneHalf(T)(T i) {
        return i >> 1;
    }
```


Also it seemed odd to me that this could compile!

SDB@79


enum functions

2023-01-08 Thread Salih Dincer via Digitalmars-d-learn

Aho,

I accidentally had a function like this:

```d
enum oneHalf(T)(T i) {
        return i >> 1;
    }
```

I'm wondering 2 things; firstly, does having an enum mean there 
is no auto-return? Or could it be CTFE?


Second, why is there no inference when I use an enum in one of 
the functions below?


```d
template foo (T) {
    enum foo = (T i) => i >> 1;
}

template bar (T) {
    auto bar (T i) => i >> 1;
}

import std;

void main()
{
assert(oneHalf(42) == 21);
    42.foo!int.writeln; // no inference: "21"
    42.bar.writeln; // "21"
}
```

Thanks...

SDB@79


Re: enum functions

2014-06-21 Thread Andrej Mitrovic via Digitalmars-d-learn
On Saturday, June 21, 2014, Paul D Anderson via Digitalmars-d-learn 
digitalmars-d-learn@puremagic.com wrote:
 Does enum have any effect on functions?

I think that's just a parser bug.


enum functions

2014-06-20 Thread Paul D Anderson via Digitalmars-d-learn

Does enum have any effect on functions?

Is this:

mixin (Constant!(ln2));
package enum T ln2(T)(Context context) {
return log(T.TWO, context, false);
}

different from this:

mixin (Constant!(ln2));
package /*enum*/ T ln2(T)(Context context) {
return log(T.TWO, context, false);
}

The spec says that enums are used to declare constants. I'm not 
sure what it means for a function to be constant. My guess would 
be that the value of the function is CTFE'd and that value is 
stored as if it were a manifest constant, but that's not what 
happens. The enum functions operate exactly like the non-enum 
functions.


So either enum functions are different in some way or they're 
not. If they are different that should be in the spec. If not, 
enum before a function declaration should not be allowed.


Paul