Re: Let's bikeshed std.experimental.testing assertions/checks/whatchamacallits

2015-07-03 Thread linkrope via Digitalmars-d

1. 'assert' is the wrong thing

I do not need a stack trace for a failed expectation in a unit 
test.
But, usually, I need a stack trace for a contract violation from 
deep down in the unit under test:


https://github.com/linkrope/dunit#failures-vs-errors

Consequently, the failed expectation should throw some "failed 
expectation" 'Exception' instead of an 'AssertError'. So, 
std.exception.assertThrown cannot be used for expectations.


2. something like an 'assert' with better diagnostics could be 
nice


Catch for C++ introduced 'REQUIRE' with helpful failure messages:

Example.cpp:9: FAILED:
  REQUIRE( Factorial(0) == 1 )
with expansion:
  0 == 1

https://github.com/philsquared/Catch

3. 'should' seems to be obsolete

Now, 'expect' should be used for expectations:

http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/


Re: D Meetup in Berlin

2014-12-05 Thread linkrope via Digitalmars-d
I would like to join. The problem is, that I'm working in Munich 
(at Funkwerk). But almost every Friday I will be in Berlin. So, 
it would be great if such a Meetup could be on a Friday.


Re: Voting: std.logger

2014-07-31 Thread linkrope via Digitalmars-d

On Thursday, 31 July 2014 at 07:13:37 UTC, Kagamin wrote:
On Wednesday, 30 July 2014 at 20:41:15 UTC, Andrei Alexandrescu 
wrote:
Yah but then we have stuttering such as log.log("ehm") which 
is oddly the same as log("ehm").


log.write
log.writef


And with

alias writef opCall;

(from the previous std.log proposal) it could also be

   log("ehm");


Re: Voting: std.logger

2014-07-30 Thread linkrope via Digitalmars-d
On Wednesday, 30 July 2014 at 18:08:12 UTC, Andrei Alexandrescu 
wrote:

On 7/30/14, 10:50 AM, linkrope wrote:
On Wednesday, 30 July 2014 at 17:01:39 UTC, Andrei 
Alexandrescu wrote:

On 7/30/14, 8:16 AM, Kagamin wrote:
On Wednesday, 30 July 2014 at 14:59:38 UTC, Andrei 
Alexandrescu wrote:

Such logic doesn't apply to vocabularies.


According to my vocabulary, a logger is something that logs. 
Didn't hear

about irater, and messer sounds like a German word.


Yah but the log object, i.e. the thing you log things in (the 
paper
log on a ship etc) is "a log", not "a logger". A "logger" 
would be the

person writing into the log.

So the appropriate name for the default log object is 
"defaultLog" not
"defaultLogger", or "stdlog" not "stdlogger". The better 
choice is

also shorter.


Andrei


Even shorter would be "log".
That would be better than enabling

log.info(...);

via the already proposed

import log = std.logger;

The only obstacle is the current "log" function.
But do we really need the free log functions? For UFCS?

Otherwise

alias info = log.info;

would do the trick.


But here we're discussing the name of the default log object... 
-- Andrei


Yes: most of the time I should be happy with the default log 
object.

Call it "log" and the uses look great:

log.error("something went wrong");


Re: Voting: std.logger

2014-07-30 Thread linkrope via Digitalmars-d
On Wednesday, 30 July 2014 at 17:01:39 UTC, Andrei Alexandrescu 
wrote:

On 7/30/14, 8:16 AM, Kagamin wrote:
On Wednesday, 30 July 2014 at 14:59:38 UTC, Andrei 
Alexandrescu wrote:

Such logic doesn't apply to vocabularies.


According to my vocabulary, a logger is something that logs. 
Didn't hear

about irater, and messer sounds like a German word.


Yah but the log object, i.e. the thing you log things in (the 
paper log on a ship etc) is "a log", not "a logger". A "logger" 
would be the person writing into the log.


So the appropriate name for the default log object is 
"defaultLog" not "defaultLogger", or "stdlog" not "stdlogger". 
The better choice is also shorter.



Andrei


Even shorter would be "log".
That would be better than enabling

log.info(...);

via the already proposed

import log = std.logger;

The only obstacle is the current "log" function.
But do we really need the free log functions? For UFCS?

Otherwise

alias info = log.info;

would do the trick.


Re: Voting: std.logger

2014-07-30 Thread linkrope via Digitalmars-d

On Wednesday, 30 July 2014 at 14:25:49 UTC, David Nadlinger wrote:
On a note less related to bikes, could anybody explain to me 
why a name is something natural to a logger? In other words, 
why does it make sense to complicate the entire design with 
this instead of just using either a set (in place of a map) in 
MultiLogger or at least keeping the whole name concept local to 
it?


Cheers,
David


In addition:
The setter property for the name of the logger together with the 
sorting of loggers by name and 'assumeSorted' will cause trouble.


Re: Voting: std.logger

2014-07-29 Thread linkrope via Digitalmars-d
On Tuesday, 29 July 2014 at 17:31:27 UTC, Robert burner Schadek 
wrote:
On Tuesday, 29 July 2014 at 17:20:58 UTC, Andrei Alexandrescu 
wrote:


I should have the overload approach done by tonight


Have a look at 
https://github.com/linkrope/log/blob/master/src/log.d#L55-66 for 
the overloading.


It's much cleaner than the 'static if' sequences.


Re: Review: std.logger

2014-07-23 Thread linkrope via Digitalmars-d
On Tuesday, 22 July 2014 at 23:43:59 UTC, Robert burner Schadek 
wrote:

On Tuesday, 22 July 2014 at 21:52:09 UTC, linkrope wrote:

Controversial conditional logging

The only advantage of
   tracec(condition, "passed");
over
   if (condition) trace("passed");
would be, that a costly evaluation of the condition is omitted 
when there is no trace logger.

That's why the std.log proposal had 'when(lazy bool now)'.

First, I was puzzled about your argument that LOG_FIRST_N or 
LOG_EVERY_N would be no problem with the '...c' functions. But 
a look at the implementation confirmed that the std.logger has 
no lazy evaluation of the condition; discarding the only 
advantage.


passing a bool as a delegate that is the first thing that gets 
evaluated does not sound right.


Indeed: that's why the lazy condition should be evaluated last!

Your "will log" condition is very simple and efficient: only >= 
and !=
But you cannot know, how long the evaluation of the user-provided 
condition will take.


BTW: with 'globalLogLevel', 'defaultLogger.logLevel'and 
'LogLevel.off' the usual 'willLog' predicate will come in handy 
to avoid code duplication.


While the lazy evaluation of the condition would be the only 
advantage over


if (condtion) log(...);

I haven't encountered a single opportunity for conditional 
logging in the code of our company.


'if'/'log' is always followed by 'return', 'break', 'continue', 
...


if (condition)
{
log("will do something else because condition passed");
return;
}


Re: Review: std.logger

2014-07-22 Thread linkrope via Digitalmars-d
Sorry, but at the first contact with the implementation (the one 
with 'genDocComment' and 'buildLogFunction' from months ago) I 
was scared away. (It's better now.)


I feared that if I criticize the 'mixin' sequences you would ask 
something like "suggestions?" ;-)
So, I made this experiment to provide an answer. Now, I can 
suggest: try something like this:


alias trace = log!(LogLevel.trace);
alias info = log!(LogLevel.info);
alias warn = log!(LogLevel.warn);
alias error = log!(LogLevel.error);
alias fatal = log!(LogLevel.fatal);

(see https://github.com/linkrope/log/blob/master/src/log.d)

Controversial conditional logging

The only advantage of
tracec(condition, "passed");
over
if (condition) trace("passed");
would be, that a costly evaluation of the condition is omitted 
when there is no trace logger.

That's why the std.log proposal had 'when(lazy bool now)'.

First, I was puzzled about your argument that LOG_FIRST_N or 
LOG_EVERY_N would be no problem with the '...c' functions. But a 
look at the implementation confirmed that the std.logger has no 
lazy evaluation of the condition; discarding the only advantage.


Sets of log levels
--
No!
Of course, I can log (trace | info) to stdout, warn.orHigher to 
stderr, and for instance info.orHigher to some file.


Simplicity

"The simplest way to achieve simplicity is through thoughtful 
reduction."


We started with tango.util.log (best described as log4j for D). 
We are happier now with a lot less functionality, but on the 
other hand with the simplest API that works.


On Monday, 21 July 2014 at 22:53:27 UTC, Robert burner Schadek 
wrote:

On Sunday, 20 July 2014 at 16:15:53 UTC, linkrope wrote:

Pros

The lighning talk about the std.logger proposal at DConf 2014 
had a positive impact.
We were able to change the "Current D Use" entry of our 
company from

   "Uses D2 / Phobos, Tango (log, xml)"
to
   "Uses D2 / Phobos, Tango (xml)".
(We got rid of tango.util.log; we still rely on the fast 
tango.text.xml.)


I didn't expect to hear from you about this, after you did not 
reply to my email about this topic.


If xml is problem for you, where is the PR?



Cons

1. I am not happy with the (reverse) hungarian-style naming

At least in the code of our company, logging a formatted 
string is the basic use case.
The function for the basic use case should not require a 
suffix letter.
The consistency argument, that 'infof' is like 'writef', does 
not fully apply:

neither 'infoln' nor 'infofln' make sense.
(In my opinion, "half consistent" is inconsistent.)


so we have gone full circle now 



Currently, suffix 'c' is used for conditional logging.
But, how will future extensions like glog's LOG_EVERY_N or 
LOG_FIRST_N be named?


That's an easy one.

```
auto a = LOG_FIRST_N(1337);

logc(a, "Hello world");

auto b = WHAT_EVERY_THE();
logc(b, "Hello world again");
```


With suffix 'e'? Suffix 'f' is already assigned!


what is 'e'?


The suffix letter sequence seems to be the road to confusion.

I would prefer the explicit naming of the previous std.log 
proposal:

   log.when(condition)(...)
However, there is only a small advantage over
   if (condition) log(...)


...



2. No support for 24/7 (server) applications

In my opinion, I really need logging for applications that 
possibly run forever.

With the FileLogger, the file will grow forever.
That's why most other frameworks provide something like a 
RollingFileLogger or some "logrotate-aware" FileLogger.


By the way: Instead of what I really need, I get a NullLogger.
I have no clue, why I never ever missed such an oddity.


That was a user request, through github. Where I asked you to 
submit PRs and issues.


Have you tried subclassing Logger? I asked for PRs in the email 
I wrote to you at least twice.




3. Implementation is hidden behind 'mixin' expressions

When I tried to look at the implementation, I found long 
sequences of lines like this:

   mixin(buildLogFunction(true, false, false, LogLevel.info));

Nowadays, this changed into:
   mixin(freeLog.format(
   "info", "info", "info", "info",
   "info", "info", "info", "info",
   "info", "info", "info", "info",
   "info", "info", "info", "info"));

This is much better, but I still think, it's a complicated 
solution for a simple problem.

And it would be a shame for D, if there is no simple solution.


Yes please, suggestions?



Small stuff
---
4. FileLogger needs flush

It's annoy

Re: Review: std.logger

2014-07-22 Thread linkrope via Digitalmars-d

On Tuesday, 22 July 2014 at 09:51:24 UTC, ponce wrote:

On Tuesday, 22 July 2014 at 08:44:06 UTC, linkrope wrote:

On Tuesday, 22 July 2014 at 07:27:38 UTC, ponce wrote:

On Sunday, 20 July 2014 at 16:15:53 UTC, linkrope wrote:
By the way: Instead of what I really need, I get a 
NullLogger.

I have no clue, why I never ever missed such an oddity.


I asked for it. And I use it, because I write libraries that 
log warnings but don't forcefully require the users to 
provide a Logger if they don't want to.
And that way, I can still write "logger.warningf" without 
"if" everywhere.


But then it's better to provide no logger (or at least no 
logger for level warning) than an artificial NullLogger.


My need is not "artificial", at least in my view.
Your opinion is different from mine. That's fine.
That's why we need someone to try to reconcile the many, many 
opinions about this.


Not the need is artificial. For example, I have the need to 
measure the performance of an application with and without 
logging.


I think, the solution is artificial. The obvious solution would 
be to register no logger at all.


Re: Review: std.logger

2014-07-22 Thread linkrope via Digitalmars-d

On Tuesday, 22 July 2014 at 07:27:38 UTC, ponce wrote:

On Sunday, 20 July 2014 at 16:15:53 UTC, linkrope wrote:

By the way: Instead of what I really need, I get a NullLogger.
I have no clue, why I never ever missed such an oddity.


I asked for it. And I use it, because I write libraries that 
log warnings but don't forcefully require the users to provide 
a Logger if they don't want to.
And that way, I can still write "logger.warningf" without "if" 
everywhere.


But then it's better to provide no logger (or at least no logger 
for level warning) than an artificial NullLogger.


Re: Review: std.logger

2014-07-21 Thread linkrope via Digitalmars-d

Pros

The lighning talk about the std.logger proposal at DConf 2014 had 
a positive impact.
We were able to change the "Current D Use" entry of our company 
from

"Uses D2 / Phobos, Tango (log, xml)"
to
"Uses D2 / Phobos, Tango (xml)".
(We got rid of tango.util.log; we still rely on the fast 
tango.text.xml.)


Cons

1. I am not happy with the (reverse) hungarian-style naming

At least in the code of our company, logging a formatted string 
is the basic use case.
The function for the basic use case should not require a suffix 
letter.
The consistency argument, that 'infof' is like 'writef', does not 
fully apply:

neither 'infoln' nor 'infofln' make sense.
(In my opinion, "half consistent" is inconsistent.)

Currently, suffix 'c' is used for conditional logging.
But, how will future extensions like glog's LOG_EVERY_N or 
LOG_FIRST_N be named?

With suffix 'e'? Suffix 'f' is already assigned!
The suffix letter sequence seems to be the road to confusion.

I would prefer the explicit naming of the previous std.log 
proposal:

log.when(condition)(...)
However, there is only a small advantage over
if (condition) log(...)

2. No support for 24/7 (server) applications

In my opinion, I really need logging for applications that 
possibly run forever.

With the FileLogger, the file will grow forever.
That's why most other frameworks provide something like a 
RollingFileLogger or some "logrotate-aware" FileLogger.


By the way: Instead of what I really need, I get a NullLogger.
I have no clue, why I never ever missed such an oddity.

3. Implementation is hidden behind 'mixin' expressions

When I tried to look at the implementation, I found long 
sequences of lines like this:

mixin(buildLogFunction(true, false, false, LogLevel.info));

Nowadays, this changed into:
mixin(freeLog.format(
"info", "info", "info", "info",
"info", "info", "info", "info",
"info", "info", "info", "info",
"info", "info", "info", "info"));

This is much better, but I still think, it's a complicated 
solution for a simple problem.

And it would be a shame for D, if there is no simple solution.

Small stuff
---
4. FileLogger needs flush

It's annoying when the events that caused a crash have been 
logged, but they never have been written to the file.


5. Suspect use of '__gshared'

The FileLogger has a field
private __gshared File file_;

In this case, "__gshared is equivalent to static".
This means that all FileLogger instances share the same file!

6. Bad naming of "StdIOLogger"

Like 'std.stdio.StdioException', the 'io' should be lower case.
If the 'StdIOLogger' logs to 'stdout', 'StdoutLogger' would be 
preferable.


7. No need for StdIOLogger

'stdout' (and 'stderr') are Files, so a FileLogger should be able 
to handle them.

A second constructor should do the trick.

8. Log levels

Many frameworks mix the types "log level" and "set of log levels" 
(for filtering).
While 'trace', ..., 'fatal' are log levels, 'all' and 'off' 
(better: 'none'?) are sets of log levels.

(I have no idea about the type of 'unspecific'.)

A clean separation would avoid confusion:
why is there 'info(...)' but not 'all(...)'?

Also, it would be easier to log for example 'trace' and 'info' to 
'stdout'.


9. Bad naming of "std.logger"

The focus of this proposal is on the log/logging API; the loggers 
are only examples.


The recommended use should be
import log = std.logger;

Then, the name "std.log" (of the previous proposal) would be more 
appropriate.


Counter Proposal

As a consequence of these issues, I once decided to spend a 
weekend to prepare a counter proposal:


http://code.dlang.org/packages/log

The design goal was simplicity. So:
- conditional logging is not supported
- no suffix letter sequences
- there is no NullLogger
- there is no MultiLogger (this functionality is implicit)
- there is no need to provide a name for a logger

I prefer 'alias' over 'mixin':
'info' is just an alias for 'log(arg)' as well as for 'log(fmt, 
args)' at log level 'info'.


Sets of log levels are implemented as (bit) sets of log levels.
A helper function lets you select the traditional >= filtering:
LogLevel.info.orHigher

For convenience, 'stdoutLogger' and 'stderrLogger' are factory 
functions that create 'FileLogger' instances.


Of course, a RollingFileLogger as well a a "RotatingFileLogger" 
(that reopens the log file on SIGHUP) are provided.


By now, this simple solution is in use in tens of thousands lines 
of commercial code.
(Where it outperforms the previously used tango.util.log 
implementation.)


Re: Review: std.logger

2014-07-15 Thread linkrope via Digitalmars-d

What does 'errorlcf' mean?

You specify log level 'error' and then you specify another log 
level ('l):

which log level wins?

The order of these modifier letters has to be 'lcf', not 'cfl', 
...?


On Tuesday, 15 July 2014 at 08:01:12 UTC, Robert burner Schadek 
wrote:

I wouldn't call them cryptic, they are in fact very easy.

l = LogLevel
c = conditional
f = printf

what is so difficult about them. Sure errorIf looks easier, but 
what

about errorLogLevelIfPrintfFormat in comparison to errorlcf