Re: implicit-context v0.0.1

2023-10-10 Thread jmh530 via Digitalmars-d-announce
On Friday, 29 September 2023 at 11:00:05 UTC, Guillaume Piolat 
wrote:

On Friday, 29 September 2023 at 08:33:56 UTC, Imperatorn wrote:

[...]


Thinking about this, it's more vs TLS variable. __gshared would 
require synchronization.


[...]


Do you have an example of how this would be used in practice with 
allocators?


Re: implicit-context v0.0.1

2023-10-06 Thread Imperatorn via Digitalmars-d-announce

On Thursday, 5 October 2023 at 22:38:35 UTC, Antonio wrote:

On Friday, 29 September 2023 at 08:33:56 UTC, Imperatorn wrote:

[...]


Context is dynamically generated/destroyed.  I developed this 
Idea in 2009 with c#. We named this  "functional context" (15 
years ago)... I found out later something similar with AOP 
(Aspects Oriented Programming) when working with Spring in java


[...]


Oh, I remember now.

Long time since I heard anyone speak about AOP. But I think it 
was a valid idea.


Re: implicit-context v0.0.1

2023-10-05 Thread Antonio via Digitalmars-d-announce

On Friday, 29 September 2023 at 08:33:56 UTC, Imperatorn wrote:
On Thursday, 28 September 2023 at 23:28:02 UTC, Guillaume 
Piolat wrote:

Hi,

Ever had a bit of feature-envy about Odin's "context" feature 
[1]? It is something used to pass "contextual" parameters, 
like a logger, an allocator, to callees. It is akin to Scala's 
"implicit parameters", or Jai contexts [2].


[...]


Interesting, what are the benefits of using this instead of 
global variables?


Context is dynamically generated/destroyed.  I developed this 
Idea in 2009 with c#. We named this  "functional context" (15 
years ago)... I found out later something similar with AOP 
(Aspects Oriented Programming) when working with Spring in java


Lets see an example

```d
long create(PersonDto person) =>
  withTransaction( (auto cnx){
// Perform person creation stuff
long personId = cnx.execute(
   "insert into people ... returning id",
   [...]
).first!long("id");
return personId;
  });

long create(CustomerDto customer) =>
  withTransaction( (auto cnx){
 long personId = create( customer.person );
 long customerId = cnx.execute(
   "insert into customers ... returning id",
   [personId, ... ]
 ).first!long("id");
 return customerId;
  });

void main(){
  withContext((){
CustomerDto customer = { code:"P001", 
person:{name:"Peter", nif:"3442543211F"}};

long customerId = create( customer );
  })
}
```

The "withTransaction" function, iternally, asks the context if 
there is an opened transaction.


* If not found:
*  It creates one and registers it into the context.
*  calls the delegate
*  commits the transaction and removes it from the context
*  returns the delegate result.
*  If an exception is thrown by the delegate, then the 
transaction is rollbacked instead commited and the exception is 
passed through to the caller.


* If found:
* Calls the delegate transparently and returns it's result


This use case of "implicit-context" works naturally in a "per 
thread context".



Stackability is nice: (this example is not so real, but a "how 
to" example):


```d
void createPersonAction() =>
  withHttpResponse( res =>
  withAuthentifiedUser( user =>
  withHttpBody!Person( person =>
  withLogger("createPersonAction", (logger) {
logger.info("Something to be logged");
auto id = withTransaction( cnx => cnx.execute(...) );
res.send(id) )
  });
```
It shoud be more natural this way ...

```d
void createPersonAction() =>
  with( auto res = implicitHttpResponse())
  with( auto user = implicitAuthentifiedUser())
  with( auto person = implicitHttpBody!Person())
  with( auto logger = implicitLogger("createPersonAction") )
  {
logger.info("Something to be logged");
with( auto cnx = implicitTransaction() )
{
   auto id =  cnx.execute(...);
   res.send(id); // Bad place... there is an oppened 
transaction here!!!

}
  };
```

... but remember than we need to manage "exceptions" dependant 
behaviours implicitly:  **with(** is not an option for AOP.



As you can see, this is not an "Object oriented dependency 
injection"... Each "withX" internally interacts with the context 
to find or create the resource and, additionally,  performs some 
functional extra proccessing (before, after and exception).


i.e.: withHttpResponse:
* if res.send is called: this is the data to be serialized as a 
result (status 202)
* if res.send is not called, then "404 not found" will be 
generated when delegate ends.
* if an exception is raised by the delegate, it will be 
transformed in an "standard" http error


As a ramarkable benefit:  it is really simple to wrap with 
mockups when testing


Problems?

* It is "runtime" generated/consumed without compilation time 
verification (i.e.: you can call createPersonAction without an 
HttpRequest in the context )... but this is a dependency 
injection assumed problem.


* You are in risk to move to "implicit context" too many things 
(remember that functions have parameters :-) )


It was only a possible use of "implicit context" :-)


Best regards





Re: implicit-context v0.0.1

2023-10-03 Thread Guillaume Piolat via Digitalmars-d-announce

On Monday, 2 October 2023 at 19:04:19 UTC, MrSmith33 wrote:
On Thursday, 28 September 2023 at 23:28:02 UTC, Guillaume 
Piolat wrote:

- manual push/pop


I wonder if `with` statement is helpful here to reduce verbosity


Do you mean with:

with(scopedContext())
{
set!int("myVar", 5);
}

ScopedContext scopedContext() { /* blah */ }

struct ScopedContext
{
~this() { context.pop; }
}


Because at a point there was such a RAII context wrapper. I 
didn't realize, `with` extends its lifetime to the scope?


Re: implicit-context v0.0.1

2023-10-03 Thread Guillaume Piolat via Digitalmars-d-announce

On Saturday, 30 September 2023 at 15:02:16 UTC, Max Samukha wrote:

When is it useful?


You can use it to troll Jonathan Blow.


OT: Apart from being marketed more like a game (streaming videos, 
and similarly "finished" at launch?) I was striked that Jai has 
already many... perlisms in the syntax.


As for the other features that makes me pause, it's SoA.
If you have SoA types you might also need SoA slices, for example 
in Odin:

https://odin-lang.org/docs/overview/#soa-data-types

Is this composable?


Re: implicit-context v0.0.1

2023-10-02 Thread MrSmith33 via Digitalmars-d-announce
On Thursday, 28 September 2023 at 23:28:02 UTC, Guillaume Piolat 
wrote:

- manual push/pop


I wonder if `with` statement is helpful here to reduce verbosity




Re: implicit-context v0.0.1

2023-09-30 Thread Max Samukha via Digitalmars-d-announce
On Saturday, 30 September 2023 at 12:40:29 UTC, Guillaume Piolat 
wrote:



When is it useful?


You can use it to troll Jonathan Blow.


Re: implicit-context v0.0.1

2023-09-30 Thread Imperatorn via Digitalmars-d-announce
On Saturday, 30 September 2023 at 12:40:29 UTC, Guillaume Piolat 
wrote:

On Friday, 29 September 2023 at 16:56:47 UTC, Imperatorn wrote:


Sounds a bit like dependency injection but for state


Possibly, I'm not familiar with dependency injection.
When is it useful?


When you want to register a bunch of objects  and then just use 
it from various places, you just state in your ctor that you want 
to use it and it will be provided by the framework.


Re: implicit-context v0.0.1

2023-09-30 Thread evilrat via Digitalmars-d-announce
On Saturday, 30 September 2023 at 12:40:29 UTC, Guillaume Piolat 
wrote:

On Friday, 29 September 2023 at 16:56:47 UTC, Imperatorn wrote:


Sounds a bit like dependency injection but for state


Possibly, I'm not familiar with dependency injection.
When is it useful?


Dependency injection is a principle of making your 
classes/functions self-contained and isolated, it means that when 
your code might need to create a resource (such as open a file to 
write data) it is instead up to the caller to provide that 
resource, but your code never does that by itself because a 
library can't possibly know the environment and restrictions of 
the target system/machine.


Simply put, you can't possibly know how to open a file in that 
system, you can't possibly know what allocator is used in the 
caller environment (think about very low-level or bare metal 
program), and so on, so instead caller must provide everything 
that your function/method/class might need to do the work.


In the most complex situations where the entire program graph is 
about to be created in the main function there is so called DI 
containers that configures all this stuff in one central place.


Re: implicit-context v0.0.1

2023-09-30 Thread Guillaume Piolat via Digitalmars-d-announce

On Friday, 29 September 2023 at 16:56:47 UTC, Imperatorn wrote:


Sounds a bit like dependency injection but for state


Possibly, I'm not familiar with dependency injection.
When is it useful?


Re: implicit-context v0.0.1

2023-09-29 Thread Imperatorn via Digitalmars-d-announce
On Friday, 29 September 2023 at 15:30:30 UTC, Guillaume Piolat 
wrote:

On Friday, 29 September 2023 at 15:00:33 UTC, Imperatorn wrote:

[...]


Only if proven on DUB.


[...]


Think of it like envvars for threads. When you launch a 
process, the launcher knows to copy the environment variables. 
With scattered TLS variables, no new thread can get a copy of 
all the "context" it may have. But with a centralized place for 
context, you will be able to do that (not implemented yet), 
which kinda improves encapsulation.


[...]


Sounds a bit like dependency injection but for state


Re: implicit-context v0.0.1

2023-09-29 Thread drug007 via Digitalmars-d-announce

On 29.09.2023 18:30, Guillaume Piolat wrote:

On Friday, 29 September 2023 at 15:00:33 UTC, Imperatorn wrote:


I think for this to be truly valuable, it would require being part of 
the language.


Only if proven on DUB.

I admit I haven't really thought about implicit parameters before your 
post, so I might be missing something.


Think of it like envvars for threads. When you launch a process, the 
launcher knows to copy the environment variables. With scattered TLS 
variables, no new thread can get a copy of all the "context" it may 
have. But with a centralized place for context, you will be able to do 
that (not implemented yet), which kinda improves encapsulation.



**Example 1: Context variables are scoped**

   In a UI library, every new widget typically get a "UI context" (that, 
or factory functions only) polluting all the constructors there is.


Solution: Just append "uiContext" variable in the context => less 
parameters.


But it could be a TLS variable, right? Yes indeed, but then you may want 
to scope that, to remove the global from being accessed outside a 
particular scope. Globals can be accessed at any time, which doesn't 
improve a public API.



**Example 2**

When my "gfm" package was forked to "gfm7", the first thing that was 
done is:
- remove all the _gl members that would only there to confirm a 
particular shared library was used => it is part of the context
- and removed all logger interface passing => also ugly and kinda never 
changes





But later I understand that the removing of gl has also disadvantages. 
In general implicit context is really the great idea


Re: implicit-context v0.0.1

2023-09-29 Thread Guillaume Piolat via Digitalmars-d-announce

On Friday, 29 September 2023 at 15:00:33 UTC, Imperatorn wrote:


I think for this to be truly valuable, it would require being 
part of the language.


Only if proven on DUB.

I admit I haven't really thought about implicit parameters 
before your post, so I might be missing something.


Think of it like envvars for threads. When you launch a process, 
the launcher knows to copy the environment variables. With 
scattered TLS variables, no new thread can get a copy of all the 
"context" it may have. But with a centralized place for context, 
you will be able to do that (not implemented yet), which kinda 
improves encapsulation.



**Example 1: Context variables are scoped**

  In a UI library, every new widget typically get a "UI context" 
(that, or factory functions only) polluting all the constructors 
there is.


Solution: Just append "uiContext" variable in the context => less 
parameters.


But it could be a TLS variable, right? Yes indeed, but then you 
may want to scope that, to remove the global from being accessed 
outside a particular scope. Globals can be accessed at any time, 
which doesn't improve a public API.



**Example 2**

When my "gfm" package was forked to "gfm7", the first thing that 
was done is:
- remove all the _gl members that would only there to confirm a 
particular shared library was used => it is part of the context
- and removed all logger interface passing => also ugly and kinda 
never changes





Re: implicit-context v0.0.1

2023-09-29 Thread Imperatorn via Digitalmars-d-announce
On Friday, 29 September 2023 at 11:00:05 UTC, Guillaume Piolat 
wrote:

On Friday, 29 September 2023 at 08:33:56 UTC, Imperatorn wrote:
Interesting, what are the benefits of using this instead of 
global variables?


Thinking about this, it's more vs TLS variable. __gshared would 
require synchronization.


Changing the theAllocator (a TLS variable) in 
std.experimental.allocator looks like this:



auto save = theAllocator;
theAllocator = myAllocator;

// do stuff with custom allocator

theAllocator = save;



Changing the allocator in implicit-context looks like this


context.push;
context.allocator = myAlloc;

// do stuff with custom allocator

context.pop;


so now that I think about it I'm not sure if there is an 
substantial advantage over simply having TLS variables. I had 
the goal of allowing .alloca on that secondary stack. If there 
is many context variables, push and pop will be a bit faster to 
write than all the temporaries.


I understand, it's more like if you mix optional parameters and 
dependency injection?


I think for this to be truly valuable, it would require being 
part of the language.


I admit I haven't really thought about implicit parameters before 
your post, so I might be missing something.


Re: implicit-context v0.0.1

2023-09-29 Thread Guillaume Piolat via Digitalmars-d-announce

On Friday, 29 September 2023 at 08:33:56 UTC, Imperatorn wrote:
Interesting, what are the benefits of using this instead of 
global variables?


Thinking about this, it's more vs TLS variable. __gshared would 
require synchronization.


Changing the theAllocator (a TLS variable) in 
std.experimental.allocator looks like this:



auto save = theAllocator;
theAllocator = myAllocator;

// do stuff with custom allocator

theAllocator = save;



Changing the allocator in implicit-context looks like this


context.push;
context.allocator = myAlloc;

// do stuff with custom allocator

context.pop;


so now that I think about it I'm not sure if there is an 
substantial advantage over simply having TLS variables. I had the 
goal of allowing .alloca on that secondary stack. If there is 
many context variables, push and pop will be a bit faster to 
write than all the temporaries.




Re: implicit-context v0.0.1

2023-09-29 Thread Imperatorn via Digitalmars-d-announce
On Thursday, 28 September 2023 at 23:28:02 UTC, Guillaume Piolat 
wrote:

Hi,

Ever had a bit of feature-envy about Odin's "context" feature 
[1]? It is something used to pass "contextual" parameters, like 
a logger, an allocator, to callees. It is akin to Scala's 
"implicit parameters", or Jai contexts [2].


[...]


Interesting, what are the benefits of using this instead of 
global variables?


implicit-context v0.0.1

2023-09-28 Thread Guillaume Piolat via Digitalmars-d-announce

Hi,

Ever had a bit of feature-envy about Odin's "context" feature 
[1]? It is something used to pass "contextual" parameters, like a 
logger, an allocator, to callees. It is akin to Scala's "implicit 
parameters", or Jai contexts [2].



So I went ahead and implement a proof-of-concept library to have 
scope globals in D with a TLS-based stack of environments. I went 
ahead and implement a minimal logger, allocator, and "user 
pointer" API on top of that context system.


It has a worse API and usability than a language solution but 
basically I think there is no big blocker, if TLS and C runtime 
are available to you.


DUB: https://code.dlang.org/packages/implicit-context

`implicit-context` is currently limited and 
suggestions/requests/forks/destroying are much welcome.


As I see it, without compiler support the pluses are:
- no hidden "context" parameter in function calls, no new ABI
- contextual parameters are a bit like "scoped globals", they 
will not change that often.


and the minuses are:
- manual push/pop
- wordy, opDispatch getter doesn't seem possible?


[1] https://odin-lang.org/docs/overview/#implicit-context-system
[2] 
https://medium.com/@christoffer_99666/a-little-context-d06dfdec79a3