January 17, 2018
On Wednesday, January 17, 2018 11:52:40 Steven Schveighoffer via Digitalmars-d wrote:
> On 1/16/18 10:59 PM, ketmar wrote:
> > Steven Schveighoffer wrote:
> >> I shudder at the thought of compiled code being affected by documentation.
> >>
> >> I don't like it, sorry.
> >
> > it's not really different from `version(DDoc)`, or string mixins, or UDAs. i can put documentation in UDA, and process code differently when UDA changes. yes, UDA is not a comment -- but it doesn't affect code generation directly too. there is just no way to stop people from writing abominations once we got metaprogramming. and adding artificial limitations on that just makes people more inventive, but won't stop infestation. ;-)
>
> version(DDoc) is very different. It's a command line option passed to the build, and affecting the build with command line options is expected.
>
> This proposal has comment *contents* affecting the build. The charter of comments is to NOT affect code, ever. They can be used to affect other systems, such as the ddoc generator, ide hints, etc., but you can be sure (?) that comments won't change code.
>
> I think this is an important line not to cross.
>
> One of the features promoted in this is to have the documentation be used for command-line help. I think it would be better to allow ddoc generation be affected by code rather than the other way around in this regard.

+1

- Jonathan M Davis

January 17, 2018
On Wed, Jan 17, 2018 at 06:24:50PM +0000, Simen Kjærås via Digitalmars-d wrote: [...]
> enum a = import(__FILE__);
> static if (a.indexOf("//") > -1) {
>     fireZeMissiles();
> }
[...]

OTOH, this combination of string import and self-referencing __FILE__ opens up a host of curious possibilities (all of which already work today, btw):

1) Trivial self-reproducing program in D:

	import std.stdio;
	void main() { write(import(__FILE__)); }

2) Self-checking programs:

	import std.algorithm;
	static assert(import(__FILE__).canFind("\n/**"),
		"Dude, why did you remove the ddoc comment?!");

	/** Remove this comment to get a compile error */
	void main() {
	}

3) Underhanded / deceptive "self-modifying" code:

	version(none) {
		// This code will never get compiled, right? Right???
		import std.stdio;
		void main() {
			writeln("Launch nuclear missiles");
		}
	} else {
		mixin(() {
			import std.array : replace;
			return import(__FILE__).replace("none", "all");
		}());
	}

These are just trivial examples, of course.  One can easily imagine more sophisticated variations that can do all sorts of weird / dangerous things.

Imagine an advanced version of (2), for example, code that will force a compilation error if it wasn't formatted correctly.

Or an advanced form of (3) where the real program code is inside an encrypted comment written in a different language that gets compiled into D by a CTFE compiler.

Or a CTFE implementation of AST macros that uses libdparse to parse itself, apply modifications, and mixin. :-D


T

-- 
"Maybe" is a strange word.  When mom or dad says it it means "yes", but when my big brothers say it it means "no"! -- PJ jr.
January 17, 2018
On Wed, Jan 17, 2018 at 02:15:08PM -0800, H. S. Teoh via Digitalmars-d wrote: [...]
> OTOH, this combination of string import and self-referencing __FILE__ opens up a host of curious possibilities (all of which already work today, btw):
[...]

Another interesting one: breaking through the barriers of modularization:

	// mod.d
	string getCode(string file = __FILE__)() {
		return import(file);
	}

	// main.d
	import mod;
	void main() {
		pragma(msg, getCode);
	}

Here, module mod gains access to the source code of a file outside of itself, and it doesn't even need prior knowledge of the filenames.  In this case nothing interesting happens, of course.  But imagine if getCode did something else, like extract private symbol definitions, or ran a syntax checker, or AST transformations, etc.. All sorts of interesting effects ensue.

Coming back on topic, one can easily imagine a CTFE D parser that basically implements __traits(documentation) as *library code*. You won't even need compiler support for that.  Wow.  Skeleton code:

	string traitsDocumentation(alias symbol, string file = __FILE__)()
	{
		enum code = import(file);
		auto s = searchForDocComment(symbol.stringof);
		return s;
	}


T

-- 
Let's call it an accidental feature. -- Larry Wall
January 18, 2018
On Wednesday, 17 January 2018 at 22:15:08 UTC, H. S. Teoh wrote:
> 2) Self-checking programs:
>
> 	import std.algorithm;
> 	static assert(import(__FILE__).canFind("\n/**"),
> 		"Dude, why did you remove the ddoc comment?!");
>
> 	/** Remove this comment to get a compile error */
> 	void main() {
> 	}
[snip]
> Imagine an advanced version of (2), for example, code that will force a compilation error if it wasn't formatted correctly.

I found an interesting Rust project a few years back, called Launch-Code:
https://github.com/kmcallister/launch-code

The idea is that unsafe functions be cryptographically signed by some authority, and the code refuses to compile if a junior dev tries and fuck with it. On a per-function basis, so he could still mess up the code that doesn't launch missiles.

We could do the same in D - parse the code with CTFE, hash the function body, then assert that the comment matches the hash. Should be fairly easy at that point to generate the signatures as well.

--
  Simen
January 18, 2018
On 1/17/18 1:24 PM, Simen Kjærås wrote:
> On Wednesday, 17 January 2018 at 16:52:40 UTC, Steven Schveighoffer wrote:
>> The charter of comments is to NOT affect code, ever. They can be used to affect other systems, such as the ddoc generator, ide hints, etc., but you can be sure (?) that comments won't change code.
>>
>> I think this is an important line not to cross.
> 
> That's already perfectly possible today:
> 
> enum a = import(__FILE__);
> static if (a.indexOf("//") > -1) {
>      fireZeMissiles();
> }

Ironically, this doesn't need any comments to trigger :)

Furthermore, I'd ask, if it's possible today, why do we need a __traits to do it? Having a __traits option for looking at documentation sounds like a very rare need in the first place to warrant promoting such a hole in the expectations for comments.

I find this to also be undesirable, and I would flag any code that used such a technique as unacceptable in code review.

-Steve
January 18, 2018
On Thursday, 18 January 2018 at 16:41:04 UTC, Steven Schveighoffer wrote:
> Furthermore, I'd ask, if it's possible today, why do we need a __traits to do it?

It is an enormous pain to do it now.... well, sort of, actually, the way I'd do it now is do a two-step makefile, where step 1 runs a ddoc generator and step 2 import("generated.html") it.

But, for stuff like little command line arg stuff, or web interface creation, it is nice to be able to print that data more conveniently. Any code that uses it in an evil way should be stupid, but writeln(__traits(documentation, foo)) is useful and not really harmless.

January 18, 2018
On Wednesday, 17 January 2018 at 02:19:11 UTC, Seb wrote:
> So do you have a good use cases for this?
> If this is a useful feature, the implementation can be improved to be zero-cost for normal runs.

If a GUI button simply executes a function. Tooltip for it could be generated from the function documentation.

About being able to use the documentation comment in mixins, of course it would be an ill recommended thing to do. But I don't think it would become much of an issue since you can hardly do that accidently.

IMO, D can already be used more dangerously than even C++ if you want to: binary imports, string mixins and static ifs can be used for far more sophiscated hacks than the C preprocessor. But it does not matter since they do not encourage or trick anybody to do the said hacks.
January 18, 2018
On Thursday, 18 January 2018 at 16:48:45 UTC, Adam D. Ruppe wrote:
> On Thursday, 18 January 2018 at 16:41:04 UTC, Steven Schveighoffer wrote:
>> Furthermore, I'd ask, if it's possible today, why do we need a __traits to do it?
>
> It is an enormous pain to do it now.... well, sort of, actually, the way I'd do it now is do a two-step makefile, where step 1 runs a ddoc generator and step 2 import("generated.html") it.
>
> But, for stuff like little command line arg stuff, or web interface creation, it is nice to be able to print that data more conveniently. Any code that uses it in an evil way should be stupid, but writeln(__traits(documentation, foo)) is useful and not really harmless.

Irony?
January 18, 2018
On 1/18/18 11:48 AM, Adam D. Ruppe wrote:
> On Thursday, 18 January 2018 at 16:41:04 UTC, Steven Schveighoffer wrote:
>> Furthermore, I'd ask, if it's possible today, why do we need a __traits to do it?
> 
> It is an enormous pain to do it now.... well, sort of, actually, the way I'd do it now is do a two-step makefile, where step 1 runs a ddoc generator and step 2 import("generated.html") it.

This is how I'd imagine doing something like this. I don't see it being a huge pain, just an extra build step.

> But, for stuff like little command line arg stuff, or web interface creation, it is nice to be able to print that data more conveniently. Any code that uses it in an evil way should be stupid, but writeln(__traits(documentation, foo)) is useful and not really harmless.
> 

Did you mean not really harmful?

But in any case, the idea that comments affect the file you are compiling *right now*, and not some other tool-generated file makes me very nervous. Comments are supposed to not affect the code. Consider that with this feature, the documentation now becomes part of the API.

-Steve
January 18, 2018
On Thursday, 18 January 2018 at 18:31:28 UTC, Steven Schveighoffer wrote:
> This is how I'd imagine doing something like this. I don't see it being a huge pain, just an extra build step.

Yeah, it isn't terrible, but it just seems heavy for something small like a command line app printing out its options.

> Did you mean not really harmful?

lol yeah.

> But in any case, the idea that comments affect the file you are compiling *right now*, and not some other tool-generated file makes me very nervous. Comments are supposed to not affect the code. Consider that with this feature, the documentation now becomes part of the API.

Meh, I see your point, I just don't agree it is that important. I'm iffy on a lot of the things people do with UFCS and optional parenthesis/properties and think it is ugly code*, but on the balance, I still like the feature.

* did you see that SO thing a bit ago about " can if(a == 1 && a == 2 && a == 3) ever be true"? Ugly code there but impure properties are useful in other cases.