www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Annotation of functions

reply psychoticRabbit <meagain meagain.com> writes:
I've noticed that Go and Rust annotate functions.

func (in go)
fn (in rust)

I was kind of wondering why they made that choice, given 
compilers in many languages do not.

Would this be a useful feature in D?

Everything else seems to have an annotation (e.g structs, 
classes.) So why not functions?

What are people's thoughts about it?

My first thought is to make it an optional annotation, for the 
benefit of developing source code analysis tools that can 'more 
easily' find functions in source code (i.e. The D compiler can 
just strip it off and do nothing with it.).  That way programmers 
that see no benefit in it, don't have to deal with it.
Feb 20 2018
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 20/02/2018 12:15 PM, psychoticRabbit wrote:
 I've noticed that Go and Rust annotate functions.
 
 func (in go)
 fn (in rust)
 
 I was kind of wondering why they made that choice, given compilers in 
 many languages do not.
 
 Would this be a useful feature in D?
 
 Everything else seems to have an annotation (e.g structs, classes.) So 
 why not functions?
 
 What are people's thoughts about it?
 
 My first thought is to make it an optional annotation, for the benefit 
 of developing source code analysis tools that can 'more easily' find 
 functions in source code (i.e. The D compiler can just strip it off and 
 do nothing with it.).  That way programmers that see no benefit in it, 
 don't have to deal with it.
You need a fully implemented frontend to get anything proper in terms of parsing for D. We're not talking about syntax highlighting here. So the point is moot.
Feb 20 2018
next sibling parent reply psychoRabbit <meagain meagain.com> writes:
On Tuesday, 20 February 2018 at 12:18:47 UTC, rikki cattermole 
wrote:
 You need a fully implemented frontend to get anything proper in 
 terms of parsing for D.
 We're not talking about syntax highlighting here.

 So the point is moot.
Why is the point (about being able to more easily find functions) moot? At the moment, i can't even grep source code for functions. i can for structs. i can for classes. but I can't for functions. if function were annotated, I could grep for that annotation. That's really the only benefit I see in it.
Feb 20 2018
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 20/02/2018 12:35 PM, psychoRabbit wrote:
 On Tuesday, 20 February 2018 at 12:18:47 UTC, rikki cattermole wrote:
 You need a fully implemented frontend to get anything proper in terms 
 of parsing for D.
 We're not talking about syntax highlighting here.

 So the point is moot.
Why is the point (about being able to more easily find functions) moot?
string creater() pure { return "void func() {}"; } mixin(creator()); That is why. There are plenty of functions, classes and structs that simply won't exist in the form of syntax until you execute CTFE.
Feb 20 2018
parent reply psychoticRabbit <meagain meagain.com> writes:
On Tuesday, 20 February 2018 at 12:45:25 UTC, rikki cattermole 
wrote:
 string creater() pure {
 	return "void func() {}";
 }

 mixin(creator());

 That is why. There are plenty of functions, classes and structs 
 that simply won't exist in the form of syntax until you execute 
 CTFE.
I think I'd fire anyone that wrote functions in that way ;-) perhaps what I had in mind was a lot simpler. fn string creater() pure { return "void func() {}"; } so now I'm just looking for lines that begin with fn. the mixin doesn't matter. the only reason I thought of this annotation thing, was so I could grep a source code file and count how many functions it had in it. this seemed the easiest way ;-) at the moment, that's just not possible - as you mentioned, you need a front end to process that kind of information (unless you have an annotation).
Feb 20 2018
next sibling parent reply psychoticRabbit <meagain meagain.com> writes:
On Tuesday, 20 February 2018 at 12:55:31 UTC, psychoticRabbit 
wrote:
 fn string creater() pure {
  	return "void func() {}";
 }

 so now I'm just looking for lines that begin with fn. the mixin 
 doesn't matter.
oh... I think I might have misunderstood your point ... due to not understanding CTFE. Never used it before - 25+ years programming ;-) what does this code even do? i don't understand it. why does it even compile? string creator() pure { return "void func() {}"; } mixin(creator());
Feb 20 2018
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Tuesday, February 20, 2018 13:04:42 psychoticRabbit via Digitalmars-d 
wrote:
 On Tuesday, 20 February 2018 at 12:55:31 UTC, psychoticRabbit

 wrote:
 fn string creater() pure {

     return "void func() {}";

 }

 so now I'm just looking for lines that begin with fn. the mixin
 doesn't matter.
oh... I think I might have misunderstood your point ... due to not understanding CTFE. Never used it before - 25+ years programming ;-) what does this code even do? i don't understand it. why does it even compile? string creator() pure { return "void func() {}"; } mixin(creator());
mixin takes a string and that string is basically copy-pasted in as code. So, in that example, you end up with mixin(creator()); being replaced with void func() {} The example shows a really basic example of a string mixin - so basic as to be pointless - but it gives you the basic idea. In general, when string mixins are used, they're actually a lot more complicated, but they can be a very useful tool for code generation. One place where they get used frequently where they actually tend to be simple is for operator overloading. e.g. this is std.datetime.date.DateTime's opBinary: DateTime opBinary(string op)(Duration duration) if (op == "+" || op == "-") { DateTime retval = this; immutable seconds = duration.total!"seconds"; mixin("return retval._addSeconds(" ~ op ~ "seconds);"); } D's overloaded operators were specifically designed to be used with string mixins in order to allow you to use the same function for overloading multiple operators. - Jonathan M Davis
Feb 20 2018
prev sibling parent reply bauss <jj_1337 live.dk> writes:
On Tuesday, 20 February 2018 at 12:55:31 UTC, psychoticRabbit 
wrote:
 On Tuesday, 20 February 2018 at 12:45:25 UTC, rikki cattermole 
 wrote:
 string creater() pure {
 	return "void func() {}";
 }

 mixin(creator());

 That is why. There are plenty of functions, classes and 
 structs that simply won't exist in the form of syntax until 
 you execute CTFE.
I think I'd fire anyone that wrote functions in that way ;-)
Why would you fire someone for writing idiomatic D? It was kind of a bad example given, but there are legitimate reasons to generate functions like that. Ex. mixin template Property(T, string name) { mixin("private T _" ~ name ~ ";"); property { mixin("T " ~ name ~ "() { return _" ~ name ~ "; }"); mixin("void " ~ name ~ "(T newValue) { _" ~ name ~ " = newValue; }"); } } mixin template ReadProperty(T, string name) { mixin("private T _" ~ name ~ ";"); property { mixin("T " ~ name ~ "() { return _" ~ name ~ "; }"); } } mixin template WriteProperty(T, string name) { mixin("private T _" ~ name ~ ";"); property { mixin("void " ~ name ~ "(T newValue) { _" ~ name ~ " = newValue; }"); } }
Feb 20 2018
parent reply bauss <jj_1337 live.dk> writes:
On Tuesday, 20 February 2018 at 13:39:17 UTC, bauss wrote:
 On Tuesday, 20 February 2018 at 12:55:31 UTC, psychoticRabbit 
 wrote:
 On Tuesday, 20 February 2018 at 12:45:25 UTC, rikki cattermole 
 wrote:
 string creater() pure {
 	return "void func() {}";
 }

 mixin(creator());

 That is why. There are plenty of functions, classes and 
 structs that simply won't exist in the form of syntax until 
 you execute CTFE.
I think I'd fire anyone that wrote functions in that way ;-)
Why would you fire someone for writing idiomatic D? It was kind of a bad example given, but there are legitimate reasons to generate functions like that. Ex. mixin template Property(T, string name) { mixin("private T _" ~ name ~ ";"); property { mixin("T " ~ name ~ "() { return _" ~ name ~ "; }"); mixin("void " ~ name ~ "(T newValue) { _" ~ name ~ " = newValue; }"); } } mixin template ReadProperty(T, string name) { mixin("private T _" ~ name ~ ";"); property { mixin("T " ~ name ~ "() { return _" ~ name ~ "; }"); } } mixin template WriteProperty(T, string name) { mixin("private T _" ~ name ~ ";"); property { mixin("void " ~ name ~ "(T newValue) { _" ~ name ~ " = newValue; }"); } }
I should probably have put an example usage to show how it's used: class Foo { mixin Property!(int, "bar"); mixin Property!(string, "baz"); } void main() { auto foo = new Foo; foo.bar = 100; foo.baz = "Hello"; import std.stdio; writeln(foo.bar); writeln(foo.baz); }
Feb 20 2018
parent reply psychoticRabbit <meagain meagain.com> writes:
On Tuesday, 20 February 2018 at 13:40:16 UTC, bauss wrote:
 I should probably have put an example usage to show how it's 
 used:
 ....
This makes we want to go back and program in C again ;-) (but thanks for taking the time to demo/explain)
Feb 20 2018
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 2/20/18 8:53 PM, psychoticRabbit wrote:
 On Tuesday, 20 February 2018 at 13:40:16 UTC, bauss wrote:
 I should probably have put an example usage to show how it's used:
 ....
This makes we want to go back and program in C again ;-) (but thanks for taking the time to demo/explain)
Mixins are one of those things that you need occasionally, but are weird to think about. But it's really akin to the C preprocessor (only better). They can be super-useful and make your life easier. For example: struct MyInt(T) { T t; auto opBinary(string op)(const MyInt other) const { return mixin("MyInt(t " ~ op ~ " other.t)"); } } void main() { import std.stdio; alias mi = MyInt!int; mi i = mi(5); writeln(i + mi(6)); // MyInt!int(11) writeln(i - mi(2)); // MyInt!int(3) writeln(i * mi(4)); // MyInt!int(20) writeln(i / mi(2)); // MyInt!int(2) writeln(i ^ mi(1)); // MyInt!int(4) ... // etc. } The other thing that always gets me are all the different "is" expressions. I never remember those things. -Steve
Feb 21 2018
prev sibling parent Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Wednesday, 21 February 2018 at 01:53:42 UTC, psychoticRabbit 
wrote:
 On Tuesday, 20 February 2018 at 13:40:16 UTC, bauss wrote:
 I should probably have put an example usage to show how it's 
 used:
 ....
This makes we want to go back and program in C again ;-) (but thanks for taking the time to demo/explain)
mixin is equivalent to preprocessor macros but with the benefit that you can build the string/macro using construct of the language and informations the compiler knows. The mixin itself corresponds then to the macro expansion.
Feb 21 2018
prev sibling parent reply psychoticRabbit <meagain meagain.com> writes:
On Tuesday, 20 February 2018 at 12:18:47 UTC, rikki cattermole 
wrote:
 So the point is moot.
ok. I've come around... and the point reall is moot. so.. in that case..another idea...how about a compiler option to output a list of functions. (I don't really expect many will warm to that idea.) Does anyone know of any tool that could do such a thing? I just want of a list of functions from a source code file. Who would have thought it would be that hard ;-)
Feb 20 2018
next sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
psychoticRabbit wrote:

 On Tuesday, 20 February 2018 at 12:18:47 UTC, rikki cattermole wrote:
 So the point is moot.
ok. I've come around... and the point reall is moot. so.. in that case..another idea...how about a compiler option to output a list of functions. (I don't really expect many will warm to that idea.) Does anyone know of any tool that could do such a thing?
dmd. dmd -X will output alot of interesting info.
Feb 20 2018
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Tuesday, 20 February 2018 at 13:27:08 UTC, psychoticRabbit 
wrote:
 so.. in that case..another idea...how about a compiler option 
 to output a list of functions. (I don't really expect many will 
 warm to that idea.)

 Does anyone know of any tool that could do such a thing?

 I just want of a list of functions from a source code file.

 Who would have thought it would be that hard ;-)
dmd -X spits out the json file with a list of functions and classes and other stuff. Then you can just filter that. Also try https://github.com/dlang-community/D-Scanner which can output such a list as a "ctags" file, which a lot of editors know how to read for jumping around. You can also use a documentation generator like mine https://github.com/adamdruppe/adrdox if you put doc comments on it and get a html and xml output, though for just finding the list I think dmd -X is going to be easier.
Feb 20 2018
next sibling parent reply psychoticRabbit <meagain meagain.com> writes:
On Tuesday, 20 February 2018 at 15:26:12 UTC, Adam D. Ruppe wrote:
 dmd -X spits out the json file with a list of functions and 
 classes and other stuff. Then you can just filter that.
'dmd -X' looks like the perfect solution for my need. thanks.
Feb 20 2018
parent reply Seb <seb wilzba.ch> writes:
On Wednesday, 21 February 2018 at 01:58:17 UTC, psychoticRabbit 
wrote:
 On Tuesday, 20 February 2018 at 15:26:12 UTC, Adam D. Ruppe 
 wrote:
 dmd -X spits out the json file with a list of functions and 
 classes and other stuff. Then you can just filter that.
'dmd -X' looks like the perfect solution for my need. thanks.
I don't know what exactly you plan to do, but the AST dump from DScanner is usually also quite handy: https://github.com/dlang-community/D-Scanner#ast-dump In fact, with libdparse, you don't get it as XML, but as AST: https://github.com/dlang-community/libdparse Example: https://run.dlang.io/is/qZsGDD
Feb 22 2018
parent psychoticRabbit <meagain meagain.com> writes:
On Thursday, 22 February 2018 at 14:50:37 UTC, Seb wrote:
 On Wednesday, 21 February 2018 at 01:58:17 UTC, psychoticRabbit 
 wrote:
 On Tuesday, 20 February 2018 at 15:26:12 UTC, Adam D. Ruppe 
 wrote:
 dmd -X spits out the json file with a list of functions and 
 classes and other stuff. Then you can just filter that.
'dmd -X' looks like the perfect solution for my need. thanks.
I don't know what exactly you plan to do, but the AST dump from DScanner is usually also quite handy: https://github.com/dlang-community/D-Scanner#ast-dump In fact, with libdparse, you don't get it as XML, but as AST: https://github.com/dlang-community/libdparse Example: https://run.dlang.io/is/qZsGDD
I want to do some cyber-security related analysis of D code bases - so looking for tools that might assist. I'll definately go have a look at dscanner and libdparse too. Thanks for the tip.
Feb 22 2018
prev sibling parent reply psychoticRabbit <meagain meagain.com> writes:
On Tuesday, 20 February 2018 at 15:26:12 UTC, Adam D. Ruppe wrote:
 dmd -X spits out the json file with a list of functions and 
 classes and other stuff. Then you can just filter that.
do you know why the first and last character of the output from "dmd -o- -X somefile.d" are [ and ] with all the json inbetween. I'm don't really know json (never had a need to know) but as I try different json parsers, the first thing I have to do (before giving it to the json parser), is strip off the first and last character of that output. so why put them there in the first place, is my question.
Feb 22 2018
parent reply rjframe <dlang ryanjframe.com> writes:
On Thu, 22 Feb 2018 10:41:48 +0000, psychoticRabbit wrote:

 On Tuesday, 20 February 2018 at 15:26:12 UTC, Adam D. Ruppe wrote:
 dmd -X spits out the json file with a list of functions and classes and
 other stuff. Then you can just filter that.
do you know why the first and last character of the output from "dmd -o- -X somefile.d" are [ and ] with all the json inbetween. I'm don't really know json (never had a need to know) but as I try different json parsers, the first thing I have to do (before giving it to the json parser), is strip off the first and last character of that output. so why put them there in the first place, is my question.
They form an array. `[1, 2, 3]` is an array of numbers, and `[{"a":1}, {"b":2}, {"c":3}]` is an array of objects.
Feb 22 2018
parent reply psychoticRabbit <meagain meagain.com> writes:
On Thursday, 22 February 2018 at 11:32:59 UTC, rjframe wrote:
 On Thu, 22 Feb 2018 10:41:48 +0000, psychoticRabbit wrote:

 On Tuesday, 20 February 2018 at 15:26:12 UTC, Adam D. Ruppe 
 wrote:
 dmd -X spits out the json file with a list of functions and 
 classes and other stuff. Then you can just filter that.
do you know why the first and last character of the output from "dmd -o- -X somefile.d" are [ and ] with all the json inbetween. I'm don't really know json (never had a need to know) but as I try different json parsers, the first thing I have to do (before giving it to the json parser), is strip off the first and last character of that output. so why put them there in the first place, is my question.
They form an array. `[1, 2, 3]` is an array of numbers, and `[{"a":1}, {"b":2}, {"c":3}]` is an array of objects.
here is my point though: ============= module test; import std.stdio, std.file, std.json; void main() { string myFile= "source.json"; // a file produced by: dmd -o- -X source.d string js = readText(myFile); JSONValue j = parseJSON( js[1..$-1] ); // why do I have to do this?? writefln("%s = %s", j["kind"].str, j["name"].str); writefln("file = %s", j["file"].str); } ==============
Feb 22 2018
parent reply ag0aep6g <anonymous example.com> writes:
On 02/22/2018 12:54 PM, psychoticRabbit wrote:
 module test;
 
 import std.stdio, std.file, std.json;
 
 void main()
 {
      string myFile= "source.json"; // a file produced by: dmd -o- -X 
 source.d
 
      string js = readText(myFile);
 
      JSONValue j = parseJSON( js[1..$-1] ); // why do I have to do this??
 
      writefln("%s = %s", j["kind"].str, j["name"].str);
      writefln("file = %s", j["file"].str);
 
 }
You don't have to remove the brackets. You just have to process the result correctly. It's not an object but an array with an object as its first element. If you're only interested in the first module (e.g. because you know that there is exactly one), you can use `j[0]["kind"]`, `j[0]["name"]`, `j[0]["file"]`. If you want to handle multiple modules, you can loop over the array: ---- foreach (size_t i, item; j) /* It's a bit silly that `foreach (item; j)` doesn't work. */ { /* ... use `item["kind"]` etc. here ... */ } ----
Feb 22 2018
parent psychoticRabbit <meagain meagain.com> writes:
On Thursday, 22 February 2018 at 13:17:42 UTC, ag0aep6g wrote:
 You don't have to remove the brackets. You just have to process 
 the result correctly. It's not an object but an array with an 
 object as its first element.
ok. I think I demonstrated that I don't know what I'm doing with the json ;-) thanks for the tips (I tried it and it worked). Now..I better go off and learn more about parsing json...
Feb 22 2018
prev sibling next sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Tuesday, 20 February 2018 at 12:15:57 UTC, psychoticRabbit 
wrote:
 I've noticed that Go and Rust annotate functions.

 func (in go)
 fn (in rust)

 I was kind of wondering why they made that choice, given 
 compilers in many languages do not.

 Would this be a useful feature in D?

 Everything else seems to have an annotation (e.g structs, 
 classes.) So why not functions?

 What are people's thoughts about it?

 My first thought is to make it an optional annotation, for the 
 benefit of developing source code analysis tools that can 'more 
 easily' find functions in source code (i.e. The D compiler can 
 just strip it off and do nothing with it.).  That way 
 programmers that see no benefit in it, don't have to deal with 
 it.
If you want to annotate your functions (rather than someone elses), you could do something like below. Ideally this would also include a compile-time check that foo is a function. Maybe use Atila's concepts library? enum Function; Function void foo() { } void main() { }
Feb 20 2018
prev sibling next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Tuesday, 20 February 2018 at 12:15:57 UTC, psychoticRabbit 
wrote:
 I've noticed that Go and Rust annotate functions.

 func (in go)
 fn (in rust)

 I was kind of wondering why they made that choice, given 
 compilers in many languages do not.
A lot of dynamic languages do too function foo() {} // javascript etc. I suspect a good chunk of it is just to make it look more familiar to them. It might also have been so they can hack up "goto definition" features in editors without a real parser...
 Everything else seems to have an annotation (e.g structs, 
 classes.) So why not functions?
The reason is just that we don't need it - the pattern of code makes it quite obvious to the compiler what is and isn't a function. But like someone else said, we can already optionally tag stuff. Two ways: enum Function; Function void foo() or a simple comment: /// function foo void foo() {} We also have various goto definition features from parsers. In fact, I added something for this to my editor just this last saturday. It is a macro that runs "doc2 --locate-symbol=name.here -" and pipes the current source code to it, then goes to the line it returns. There's also `dmd -X` and `dscanner` both of which can read a list of files you give it and find a definition. (mine is different in two ways: 1) it looks up in scope and can do fully-qualified names and 2) it works with pipes instead of written files, so it can parse on demand) $ cat simpledisplay.d | ~/program/d-diff/doc2 --locate-symbol SimpleWindow.impl - 2018 and, of course, 2018 is the line where impl is introduced. impl is a mixin template btw - so the parser approach works on more than just functions!
Feb 20 2018
prev sibling parent Tony <tonytdominguez aol.com> writes:
On Tuesday, 20 February 2018 at 12:15:57 UTC, psychoticRabbit 
wrote:
 I've noticed that Go and Rust annotate functions.

 func (in go)
 fn (in rust)

 I was kind of wondering why they made that choice, given 
 compilers in many languages do not.
On Tuesday, 20 February 2018 at 12:15:57 UTC, psychoticRabbit wrote:
 I've noticed that Go and Rust annotate functions.

 func (in go)
 fn (in rust)

 I was kind of wondering why they made that choice, given 
 compilers in many languages do not.
I think it is common to have a keyword used in function definition - outside the C-family. The Pascal family has keywords for function and procedure declaration, as does Fortran. It looks like Cobol uses the "function" keyword for when you call a function and "function-id" for when you define it. Perl, Python and Ruby all have a keyword for function definition.
 Would this be a useful feature in D?

 Everything else seems to have an annotation (e.g structs, 
 classes.) So why not functions?

 What are people's thoughts about it?
I think keywords for functions may be to avoid or minimize the difficulty C and C++ have with declaring (and deciphering the declarations of) function pointers. Seems it also would have prevented years of C++ having "the most vexing parse", where a class instantiation can be confused with a function declaration.
Feb 21 2018