Re: D safety! New Feature?

2016-08-05 Thread Mark J Twain via Digitalmars-d

On Friday, 5 August 2016 at 21:12:06 UTC, ag0aep6g wrote:

On 08/05/2016 09:39 PM, Mark J Twain wrote:

In the case of ImmutableQueue, There is no Enqueue!

See, there is a difference between "not callable" and "does 
not exists".


Ok, but what cool stuff is enabled by "does not exist" that 
doesn't work (as nicely) with "not callable"? As far as I can 
tell, there is no difference in practice.


[...]
`immutability` only logically makes something immutable, as it 
can
easily be proved. One can cast out immutable and mutate very 
easily(take

address, change values).


Casting immutable away and then mutating is not allowed by the 
language. It has undefined behavior. After doing it, the 
program may see the old value, it may see the new value, it may 
crash, or it may behave completely crazy.


Some example code that shows different outcomes of mutating 
immutable data:



void main()
{
import std.stdio;

immutable int i = 1;
* cast(int*) &i = 2;
writeln(i); /* prints "1" */
writeln(*&i); /* prints "2" */

immutable int* p = new int(3);
*(cast(int*) p) = 4;
writeln(*p); /* prints "4" */

immutable(char)[] s = "a";
(cast(char[]) s)[0] = 'b'; /* segfault on Linux */
writeln(s); /* prints "b" on Windows */
}


That's not a valid D program at all, of course. All of the 
mutations are invalid.



`Immutable` cannot be cast because there is no
type relationship.


You can cast between completely unrelated types no problem:


struct MutableSomething
{
int value;
void mutate(int newValue) { value = newValue; }
}

struct ImmutableSomething
{
int value;
/* no mutate method here */
}

void main()
{
auto i = ImmutableSomething(1);
(cast(MutableSomething) i).mutate(2);
import std.stdio;
writeln(i.value); /* prints "2" */
}



wow, that seems like a huge design issues.

Change one value to double though and it won't work. It's not 
general and seems to be a design flaw. It is not proof of 
anything in this case though. Why? Because an Queue might not 
have the same size as an ImmutableQueue and your "proof" only 
works when they are the same size.




[...]
What I would say to you is, either try it on some examples, or 
don't.


I'm asking you for an example, because I don't see the point of 
it.


What kind of example? I have already given examples and proved 
that there is a functional difference. I will not continue this 
conversation because you refuse accept that. First you haven't 
given your criteria for me to prove anything to you to satisfy 
whatever it is you want. Second, I'm not here to waste my time 
trying to prove the merits of the tool. Again, either use it if 
you feel like it does something or don't. The method is not 
flawed in and of itself. It works(if it didn't, someone would 
have probably already shown it not to work).


All you can do is assert a negative, which you can't prove 
yourself. So we end up chasing each other tails, which I refuse 
to do. If you want more proof then it is up to you, not me. I 
have my proof and it is good enough for me.








Re: D safety! New Feature?

2016-08-05 Thread Mark J Twain via Digitalmars-d

On Thursday, 4 August 2016 at 18:58:18 UTC, ag0aep6g wrote:

On 08/04/2016 08:22 PM, Mark J Twain wrote:
The problem is that you have fixated on the *array* and not 
the general

principle. The Array was an example.


I'm having trouble understanding what you're getting at, so I'm 
trying to get it from the example you gave. If there's merit in 
your idea, then surely you can give a example where it provides 
benefit over the immutable keyword.



Get Array out of your mind and
think of them as general structures. It could be a queue.


Ok.


D has no built
in queue, then what?


You can still have an immutable queue, or a queue of immutable 
elements. Just like with arrays.



What if it is a widget, then what? Immutable Widget
vs Mutable Widget.

Marking a widget immutable is not the same as having an 
ImmutableWidget.

Can you see the difference?


No.


I assure you there is.


Please show.


The immutable keyword
only prevents data manipulation, it does not change the 
interface.


I'm still not sure what that means. An immutable object does 
not have mutating operations in its interface. A mutable object 
does. So the interfaces are different.



For
simple primitives, there is not much difference, but for 
larger complex

types, the immutable keyword doesn't cut it.

immutable Queue!int q1;
ImmutableQueue!int q2;

q1.Enqueue(x);  // Compile time error if no tricks, but the 
error is
further up the line inside Enqueue, when it actually modifies 
the data.


Not true. Since Enqueue isn't marked const or immutable, it 
can't be called on an immutable object. The compiler rejects 
the call itself. It doesn't reject the mutation that happens 
inside Enqueue, because that's perfectly fine in a non-const, 
non-immutable method.


In code:


struct Queue
{
void Enqeue(int dummy) {}
}

void main()
{
Queue m;
m.Enqeue(1);
immutable Queue i;
i.Enqeue(2); /* Error: mutable method test.Queue.Enqeue is 
not callable using a immutable object */

}


We can cast away immutability and end up defeating the purpose 
and end

up with run-time problems.


You can break everything with casts, yes.


q2.Enqueue(x);  // Compile time error, Enqueue doesn't exist in
ImmutableQueue.


It doesn't exist for an immutable Queue, either.


cannot cast away immutable.


You can still cast from ImmutableQueue to MutableQueue.


At most we can convert q2 to
a mutable class, which is a copy, then replace q2 with the 
copy.


There are difference and the second case is better. The error 
reporting
is more accurate and no casting can be done to bypass 
immutability.


We
essentially get all this stuff for free if we simply use 
templates to

build the hierarchy and separate the template in to different
parts(immutable, mutable, etc).

Now, an ImmutableQueue might not be hugely useful if we have 
no way to
access the data, but it could provide [] access. Again, don't 
get bogged
down in the specifics, I'm talking about general application 
here. The
more complex the type and hierarchy the more useful such a 
method is and

the less useful immutable keyword is.

The immutable keyword is a blind, it only does one thing. 
Building
immutability in to the type system itself allows the 
programmer to make

immutable smarter and control exactly what it does.


Sorry, but I still don't see what ImmutableWhatever does that 
`immutable Whatever` can't do. As far as I see, your example 
about having better error locations is wrong.


Ok, Simple:

immutable does not remove the interface! Regardless of how you 
are thinking about it, your exmaple, i still have Enqueue. Only 
the compiler has stopped compiling.



struct Queue
{
void Enqeue(int dummy) {}
}

void main()
{
Queue m;
m.Enqeue(1);
immutable Queue i;
i.Enqeue(2); /* Error: mutable method test.Queue.Enqeue is 
not callable using a immutable object */

}


In the case of ImmutableQueue, There is no Enqueue!

See, there is a difference between "not callable" and "does not 
exists". It seems maybe minor, and maybe it is, but immutability 
and "Immutability" are not exactly the same. I actually think 
they would work well together, and of course, a lot of overlap 
exist.


`immutability` only logically makes something immutable, as it 
can easily be proved. One can cast out immutable and mutate very 
easily(take address, change values). `Immutable` cannot be cast 
because there is no type relationship. Any time a change has to 
be made to an Immutable object, a copy is created. Of course, one 
could call this a "long winded cast", but it's more safe and 
requires more verbosity, hence less ambiguity and therefore less 
problems.


Again, there is a lot of overlap, I'm not claiming this replaces 
`immutable`. But it does things that immutable doesn't. I'm not 
even claiming it is perfect in and of itself. After all, it is 
somewhat arbitrary. One has to design the templates to be 
immutable, and if they are not then it means nothing and just 
repre

Re: Self Optimizing Code

2016-08-04 Thread Mark J Twain via Digitalmars-d

On Thursday, 4 August 2016 at 11:35:41 UTC, crimaniak wrote:

On Tuesday, 2 August 2016 at 22:06:38 UTC, Mark "J" Twain wrote:

Instead, a better solution would be to use variables:

if (n*length > m*capacity) expand(l*length)


Some time ago I played with self-optimizing cache layer.
Problem: Time to obtain cache items is unknown and server 
dependant. For example, network can be involved in this. 
Sometimes is it localhost, sometimes server on another 
continent. Time to cache it is unknown too. For example if 
memcached extension is not installed on this server then 
fallback to disk backend will slow cache performance very much. 
So we don't know is it worst to cache.

Solution: cache measures own performance and acts accordingly.



I did not think of this in terms of networking. I suppose it can 
be used there too but, as you mention, latency could be a factor.



So I make next things:
1. Functional interface instead of save/load type interface. 
cacheLevel.get(functor_to_get_item) allow to measure item 
obtaining time.
2. Implement all measuring/controlling logic in separate class 
with interface AbstractStatist, in CacheLevel class make just 
hooks for it. So changing AbstractStatist implementation I can 
change work mode to measure statistics and use it or work as 
usual cache (EmptyStatist for all empty hooks). I make 
implementation to skip all items not worst caching 
(calcTime/calcHits*totalHits-totalTime < 0) but it's possible 
to make more smart things (like caching only most efficient 
items not exceeding cache size).


If it is more complex, that what I described, it would have to be 
thought out a great deal. My goal was to simply have the program 
expose optimization points(variables) then allow an optimizer to 
change those to find better points. The program itself would be 
virtually unmodified. No code to interact with the optimization 
process except to use variables instead of constants(which is 
minimal and necessary).


Exposing an interface for the program itself to guide the 
optimization process seems like a lot more work. But, of course, 
ultimately is better as it allows more information to flow in to 
the optimization process. But this design is beyond what I'm 
willing to achieve(this way could be months or years to get done 
right), while my method could take just a few hours to code up, 
and is rather general, although a bit dumb(fire and forget and 
hope for the best).



In my experience I can draw some conclusions.
1. It need to separate measure mode and control mode. You can't 
have accurate statistics while changing system behavior 
according to current statistics state.
2. Statistics can be different for different applications but 
for specific application in specific conditions for most cases 
it can be approximated as constant.




Yes, it is tricky to make the algorithm stable. This is why I 
think, for a simple optimizer, it would need to do this over long 
periods(months of program use). Because there are so many 
aberrations(other programs, user behavior, etc), these can only 
be statically removed by repetitive uses. Essentially "low pass 
the data to remove all the spikes" then compare the avg result 
with the previous.



So for array allocating strategy more realistic scenario the 
next, I think:
1. Application compiled in some 'array_debug' mode then some 
statist trait added to array, collect usage statistics and 
writes optimal constants at the application exit.
2. Programmer configure array allocator in application 
according to these constants.
3. Application builds in release mode with optimal allocation 
strategy and without any statist overhead and works fast. Users 
are happy.


This is more static profiling type of optimizations. I am talking 
about something a bit different.  Both methods could be used 
together for a better result, but mine is for simplicity.  We 
generally blindly set constants for things that affect 
performance. Let's simply turn those constants in to variables 
and let a global blind optimizer try to figure out better values 
than what we "blindly" set. There is no guarantee that it would 
find a better result and may even introduce program instability. 
But all this stuff can be somewhat measured by cpu and memory 
usage and given enough parameters, there is probably at least 
several optimal points the optimizer could find.


Ultimately for just a little work(setting the variables and 
specifying their ranges and step, say), we could have most 
programs being created, in D for now at least, optimizing 
themselves(while they are being used by the user after they have 
been shipped) to some degree.  This, I believe, is unheard of. It 
represents the next level in program optimizations.


Imagine one day where a program could optimize itself depending 
on the hardware of the user, the users habits, etc. Well, this 
method attempts to get that ball rolling and does all those 
things in a general way(albeit ignorant, but may

Re: Self Optimizing Code

2016-08-04 Thread Mark J Twain via Digitalmars-d

On Thursday, 4 August 2016 at 04:41:43 UTC, Chris Wright wrote:
In your example, you have a size_t or double factor for array 
growth. If you set it to -1, you would have an unpleasant time. 
You need a way to specify the range of valid values. In more 
complex algorithms, you need a way to evaluate several 
parameters together to determine if they are valid.




Yes, I mentioned that, but there is no ideal way to do this. I 
think it shouldn't be done in code since it clutters the code. 
The parameter tuples are the groupings, I think the compiler can 
infer groupings based on source code closeness(if 3 parameters 
show up on the same line, it's obviously save to assume they go 
together). Ultimately there is no big deal about grouping because 
one can view the parameter space of tuples as flat.


Since you're not always optimizing for the same thing (time vs 
memory; wasted memory vs number of reallocations; for 
approximation algorithms, how good an approximation is 
generated), you need a way to specify that as well.


Well, it depends. If performance is cpy cycles and memory, then 
they are relatively easy to get, although absolute accuracy would 
be required.


Putting that in the language would be horribly complex. It 
would be much simpler for everyone if it were in a library 
instead. I could probably code up a basic version in a couple 
hours. Which I'll do for US$150 -- below market rate, 
especially since I'd continue supporting it.


or you could pay me 150$ and I'd do it. But I have better things 
to do, and without compiler support, or a preprocessor, I'm not 
interested in the code complexity a library solution would have. 
Having to specify every parameter with some long sequence of 
characters just makes it messy.


I would have to disagree about the language complexity though. At 
most the hardest part would be figuring out what syntax to use 
for symbols.


$(10,0,100,1)

Could be used. When ever the compiler comes across such a thing 
it simply


1. creates an "anonymous" variable with value 10.
2. Emits something like

test.d#43(10,0,100,1), 0x043245

(file,line,default value,min,max,step,address)

One could allow for group indexing or "closeness" by code. e.g., 
$(10,0,100,1,43) is of group 43. 0x043245 which is the address.


That would be it on the compiler side. The optimizer then has 
enough information to work from.


While such a method may lack enough information to be optimized 
effectively, in
theory, it would be enough to find the optimal parameters in the 
long term.


One could probably get away with a two or three line code for the 
variables that does the same.


auto x = Opt_Var(10, 0, 100, 1, 43);

then use x in the code. The hard part might be getting the 
relative address and absolute addresses setup properly for the 
optimizer.


Might work but still a bit cluttery IMO.

If you feel like implementing it for the benefit of humanity, be 
my guest. Else I'll end up trying in the future when I get around 
to it.



Furthermore, your idea of changing compile-time constants 
without recompiling the program is unworkable. Constants are 
folded and inlined. That "* 2" might turn into "<< 1". A loop 
based on a constant can be unrolled.


This is why I said they were variables. I said they were 
effectively constants. They obviously can't be constants. We have 
to have an address that holds the value so it can be changed by 
the optimizer.


You suggested that we can do a random walk on values to find 
optimal values. This will find a local minimum, which might not 
be the globally optimal value. Something like simulated 
annealing would work better in the general case. Simulated 
annealing is a fair bit more complex than a random walk; it's 
not going to be implemented inside druntime.


Well, there are many optimization methods, that isn't the point. 
The optimizer can be exposed for modification and different 
methods could be used. My main point was to introduce the idea. I 
have never seen it mentioned in literature before. The ability 
for a program to slowly optimize itself over it's life cycle 
seems to be a new and novel concept.


The benefit of such a thing? Not sure. May only improve 
performance 1 or 2%. The real benefit? Who knows, but as time 
goes on it might become real useful and be part of the profiling 
process and find better ways to optimize programs that give 
better results.








Re: D safety! New Feature?

2016-08-04 Thread Mark J Twain via Digitalmars-d

On Thursday, 4 August 2016 at 13:08:11 UTC, ag0aep6g wrote:

On 08/03/2016 09:33 PM, Mark J Twain wrote:
The built in array is mutable and exposes the same interface 
for the
immutable copy. The only difference is that the immutable copy 
is marked

immutable.


I don't understand. An immutable array does not let you 
overwrite elements. A mutable array does. So they have 
different interfaces, don't they?


My method changes the interface. An "immutable" type has an 
immutable

interface while a mutable type has a mutable interface.

For simple types, and value types, there is obviously no 
advantage...

their interfaces are essentially empty/DNE.


Can you show some example code where there is an advantage over 
built-in arrays?


[...]
As far as I see, "marking for reuse" is practically the same 
as
freeing here. If Data were static, there could be a 
difference.


For built-in arrays, you can mark an array for reuse by 
setting the

length to 0 and calling assumeSafeAppend, like so:


No again. Data in the example above is a local variable that 
allocates
memory that would generally be free'ed at the end of the 
function call.
Hence every call to foo results in a malloc/free pair for 
Data.  By

reusing the memory, if possible, one can potentially skip the
malloc/free.  Therefore instead of potentially thrashing the 
memory
pool, after a few runs of foo, Data would generally not 
allocate.



[...]
Your assumeSafeAppend works while the object is in existence. 
This thing

works between the existence of the object.


The allocator (e.g. the GC) is free to reuse memory it obtained 
from the operating system. So repeatedly allocating and freeing 
the same amount of memory can already be faster than one might 
think.


Of course, the compiler is also free to reuse stuff, if it's 
guaranteed that no reference escapes the function. I don't 
expect dmd to do stuff like this. ldc or gdc might.


What do Mutable/ImmutableArray enable beyond this? What do they 
do that built-in arrays don't? Again, example code would help 
doofuses like me make sense of this.


The problem is that you have fixated on the *array* and not the 
general principle. The Array was an example. Get Array out of 
your mind and think of them as general structures. It could be a 
queue. D has no built in queue, then what? What if it is a 
widget, then what? Immutable Widget vs Mutable Widget.


Marking a widget immutable is not the same as having an 
ImmutableWidget. Can you see the difference? I assure you there 
is. The immutable keyword only prevents data manipulation, it 
does not change the interface. For simple primitives, there is 
not much difference, but for larger complex types, the immutable 
keyword doesn't cut it.


immutable Queue!int q1;
ImmutableQueue!int q2;

q1.Enqueue(x);  // Compile time error if no tricks, but the error 
is further up the line inside Enqueue, when it actually modifies 
the data. We can cast away immutability and end up defeating the 
purpose and end up with run-time problems.


q2.Enqueue(x);  // Compile time error, Enqueue doesn't exist in 
ImmutableQueue. cannot cast away immutable. At most we can 
convert q2 to a mutable class, which is a copy, then replace q2 
with the copy.


There are difference and the second case is better. The error 
reporting is more accurate and no casting can be done to bypass 
immutability. We essentially get all this stuff for free if we 
simply use templates to build the hierarchy and separate the 
template in to different parts(immutable, mutable, etc).


Now, an ImmutableQueue might not be hugely useful if we have no 
way to access the data, but it could provide [] access. Again, 
don't get bogged down in the specifics, I'm talking about general 
application here. The more complex the type and hierarchy the 
more useful such a method is and the less useful immutable 
keyword is.


The immutable keyword is a blind, it only does one thing. 
Building immutability in to the type system itself allows the 
programmer to make immutable smarter and control exactly what it 
does.












Re: Self Optimizing Code

2016-08-03 Thread Mark J Twain via Digitalmars-d

On Thursday, 4 August 2016 at 01:54:57 UTC, Chris Wright wrote:

On Wed, 03 Aug 2016 21:09:46 +, ikod wrote:
This is not just profiling, but "Profile-Guided Optimization 
(PGO)"


The person is talking about algorithms with tuning parameters 
(like array growth rate when appending) adjusting those 
parameters based on observed characteristics of the program. 
For instance, if it's observed that arrays of a given type tend 
to grow to ~1800 entries or stay under 100 entries, the runtime 
might automatically extend your array from length 128 to 2048 
directly instead of growing to 256, then 512, then 1024, and 
finally 2048.


A compiler would not be allowed to make these changes 
automatically.


There are significant downsides. You need a lot of bookkeeping 
to determine what values you need. The values are not preserved 
across runs. You need to implement it separately for each 
algorithm.


You generally only bother when the potential performance gains 
are great as an absolute measure and relative to the amount of 
bookkeeping you would have to do. For instance, with array 
appending, it's a terribly common operation, so you can only 
use this technique productively if gathering the data is dirt 
cheap.


Close. I am only talking about adding the features to do such 
things and not having the compiler involved in the analysis. We 
can already do this sort of thing but it requires more 
boilerplate code and and the benefit may be negligible.


What it does for us is allows us to change hard coded values into 
special variables that then can be manipulated(if desired, or 
left alone) while the program is executing. All the compiler does 
is take these special variables and stores them in chunks(tuples) 
and possibly stores some discriminatory info about them like the 
file and function they were used in. Then it is up to the 
optimizing algorithm do decide how to approach using them. If it 
does nothing, then the only performance hit is that variables 
were used instead of hard coded literals.


A bit more info may be required for the optimizer to make good 
choices though. Since the data collected could be extremely 
large(thousands of tuples). This creates a very large parameter 
space and knowing what parameter changes created what performance 
changes is crucial(although a blind sort of parameter space 
montecarlo method could work, but would produce erratic behavior).


The optimizations would persist between program executions simply 
by writing out all the current parameter values, else it would be 
difficult for the program to ever actually optimize itself. 
Neural networks could be used to find more optimized conditions. 
It could be extended to include more dynamic characteristics of a 
program, like what JIT does, but I think this adds far more 
complexity and would require much more compiler support and would 
then probably just end up with a JIT like environment.


Another simple example. Suppose one has a sleep(10) in a thread. 
The 10 was "arbitrarily" chosen. Instead, if we could 
dosleep($10), 10 becomes a parameter. The compiler emits it to a 
file along with it's address(it is a global in the program 
address space). The optimizer then reads the file, attempts to 
modify this value with a slight perturbation, say to 11. Checks 
the performance impact(over many uses, to remove statistical 
deviations) and if it is more performant, it then uses that value 
as the default. It can then try 12 and repeat the process.  While 
the algorithm is not advanced, it is produces a more optimal 
result than hard coding the value to 10, which then cannot change 
for the life of the program. To keep the program stable, such 
changes would have to occur very slowly. Better algorithms, and 
better profiling tools(which, say, could do wider sampling and 
better performance analysis), could hone in on good values from 
the get go. Then the program itself adjusts to the individual 
user case by analysis.




Re: Self Optimizing Code

2016-08-03 Thread Mark J Twain via Digitalmars-d

On Wednesday, 3 August 2016 at 21:09:46 UTC, ikod wrote:
On Wednesday, 3 August 2016 at 19:25:08 UTC, Mark "J" Twain 
wrote:

On Wednesday, 3 August 2016 at 18:18:51 UTC, ikod wrote:
On Tuesday, 2 August 2016 at 22:06:38 UTC, Mark "J" Twain 
wrote:

Another new D feature here!

Self-Optimizing Code is a fantastic research area that can 
lead to greater improvements in code, make them more 
responsive to individual applications, and requires very 
little effort.




Looks like this:

https://wiki.dlang.org/LDC_LLVM_profiling_instrumentation


No, I don't think so. The best I can tell is this is just 
profiling. This would be having the program itself profile


This is not just profiling, but "Profile-Guided Optimization 
(PGO)"


Yes, but that is still profiling. It is static profiling while I 
am talking about dynamic profiling. It is similar, but it doesn't 
happen while the program is in use by the user.


That is, simply, the programmer runs the profiler and it 
optimizes the code then ships it as final to the user. I am 
talking about the user running the program and the program 
optimizes itself. Big difference!




Re: D safety! New Feature?

2016-08-03 Thread Mark J Twain via Digitalmars-d

On Wednesday, 3 August 2016 at 08:09:41 UTC, qznc wrote:

On Tuesday, 2 August 2016 at 21:48:58 UTC, Mark Twain wrote:

global ImmutableArray!int Data;


MutableArray!int DataCopy = Data.Copy; // Creates a mutable 
copy of Data.

... Do work with DataCopy ...
Data.Replace(DataCopy); // Makes a copy of DataCopy.


I see the problem that you cannot compose this. Expand the 
example to two global arrays:


global ImmutableArray!int Data1;
global ImmutableArray!int Data2;

MutableArray!int DataCopy1 = Data1.Copy;
MutableArray!int DataCopy2 = Data2.Copy;
 ... Do work with DataCopy1 and DataCopy2 ...
Data1.Replace(DataCopy1);
// in between state is inconsistent => unsafe
Data2.Replace(DataCopy2);


I don't see this at all.  What in between state are you talking 
about?  Each object has it's own copy so no inconsistency is 
possible. If you are saying that Data1 and Data2 are suppose to 
be consistent as a pair, then your doing it wrong. You should 
combine them in to a single structure. The same problem would 
exist with other techniques. You have acted like the order of 
declaration matters but your example, given the information, can 
be written as



global ImmutableArray!int Data1;
MutableArray!int DataCopy1 = Data1.Copy;

//

Data1.Replace(DataCopy1);




global ImmutableArray!int Data2;
MutableArray!int DataCopy2 = Data2.Copy;

//

Data2.Replace(DataCopy2);








Re: D safety! New Feature?

2016-08-03 Thread Mark J Twain via Digitalmars-d

On Wednesday, 3 August 2016 at 05:44:42 UTC, ag0aep6g wrote:

On 08/02/2016 11:48 PM, Mark Twain wrote:

global ImmutableArray!int Data;


MutableArray!int DataCopy = Data.Copy; // Creates a mutable 
copy of Data.

... Do work with DataCopy ...
Data.Replace(DataCopy); // Makes a copy of DataCopy.


What benefit do ImmutableArray and MutableArray have over 
built-in arrays? The thing above can be done with built-in 
arrays:



immutable(int)[] Data;
int[] DataCopy = Data.dup; // Creates a mutable copy of Data.
... Do work with DataCopy ...
Data = DataCopy.idup; // Makes a copy of DataCopy.




The built in array is mutable and exposes the same interface for 
the immutable copy. The only difference is that the immutable 
copy is marked immutable.


My method changes the interface. An "immutable" type has an 
immutable interface while a mutable type has a mutable interface.


For simple types, and value types, there is obviously no 
advantage... their interfaces are essentially empty/DNE.



[...]

void foo()
{
MutableArray!int Data;
scope(Exit) Data.Reuse();
}

Reuse can simply mark the memory reusable rather then freeing 
it. This
memory can then be reused the next time foo is called(or 
possibly use

the stack for memory).


As far as I see, "marking for reuse" is practically the same as 
freeing here. If Data were static, there could be a difference.


For built-in arrays, you can mark an array for reuse by setting 
the length to 0 and calling assumeSafeAppend, like so:


No again. Data in the example above is a local variable that 
allocates memory that would generally be free'ed at the end of 
the function call.  Hence every call to foo results in a 
malloc/free pair for Data.  By reusing the memory, if possible, 
one can potentially skip the malloc/free.  Therefore instead of 
potentially thrashing the memory pool, after a few runs of foo, 
Data would generally not allocate.


When one has hundreds of functions allocating and deallocating 
memory, this is a big deal. This is effectively caching or 
similar memory pooling.


Your assumeSafeAppend works while the object is in existence. 
This thing works between the existence of the object.





Re: Self Optimizing Code

2016-08-03 Thread Mark J Twain via Digitalmars-d

On Wednesday, 3 August 2016 at 18:18:51 UTC, ikod wrote:

On Tuesday, 2 August 2016 at 22:06:38 UTC, Mark "J" Twain wrote:

Another new D feature here!

Self-Optimizing Code is a fantastic research area that can 
lead to greater improvements in code, make them more 
responsive to individual applications, and requires very 
little effort.




Looks like this:

https://wiki.dlang.org/LDC_LLVM_profiling_instrumentation


No, I don't think so. The best I can tell is this is just 
profiling. This would be having the program itself profile itself 
and make modifications itself(of course, limited to these 
"special variables").





Re: Self Optimizing Code

2016-08-03 Thread Mark J Twain via Digitalmars-d

On Wednesday, 3 August 2016 at 07:36:21 UTC, ketmar wrote:

hello, you just invented JIT compiler.


Um, no. JIT = Just in time compilation. The code is already 
compiled and in binary form. The only differnece is that hard 
coded values = literals in the binary, become variables. There is 
no recompliation. The variables are simply updated by an 
optimization routine. They could be manually updated by the user, 
for example, but the user is not intelligent with regards to 
these things(although an interface for the user could be used).


Regardless, this is not JIT. Having seen some of your posts, I 
know you won't admit your ignorance here, but unless you are 
going to claim that DMD is JIT, then this is not JIT. Why? It can 
already be done in DMD without using any advanced techniques. The 
problem is that it requires the programmer to do more boilerplate 
code than is needed.


This is more akin to GC, but instead of managing memory 
references, it manages variables. Instead of freeing stuff, it 
perturbs them. But does so in the background too... but does not 
need to "stop the world", since as far as the program is 
concerned, these special variables like literals(immutable at 
least).







Re: D safety! New Feature?

2016-08-02 Thread Mark J Twain via Digitalmars-d

On Tuesday, 2 August 2016 at 21:48:58 UTC, Mark Twain wrote:

[...]


Another useful feature I forgot to mention is that we can cast 
between Immutable and Muttable types.


class ImmutableTest
{
private MutableArray!int data;
public ImmutableArray!int Data;

this()
{
// Creates a view to data, but Data cannot modify data.
Data.View(data);
}

public Add(int x)
{
data.Add(x);
}
}

Data can then be exposed without worrying about it getting 
trampled on. Sense a MutableArray contains all the functionality 
of an ImmutableArray, there should be no problems with the 
interpretation.


Self Optimizing Code

2016-08-02 Thread Mark J Twain via Digitalmars-d

Another new D feature here!

Self-Optimizing Code is a fantastic research area that can lead 
to greater improvements in code, make them more responsive to 
individual applications, and requires very little effort.



To demonstrate:

In many programs, memory behavior is fixed to a large degree, if 
not completely. Take the typical dynamic data structure that over 
allocates the required memory to store it's data by some factor, 
usually 2.


We might have code like

if (length >= capacity)
expand(2*length);

These types of expressions are used through a program. They are 
hard coded values that are generally somewhat arbitrary. They 
definitely are not optimal in all cases.


Instead, a better solution would be to use variables:

if (n*length > m*capacity) expand(l*length)

n,m, and l are not variable and can change.

How is this useful you say? Because of mathematics!

In a typical program we will have N tuples, where each tuple t_i 
is a parameter set, such as t_k(n,m,l).


This forms a vector space and, due to mathematics, we can find 
optimal values for the different parameter sets by observing the 
outcome of small perturbations over long times.


e.g., we intially start with our hard coded values as defaults.

t_i_0(1,1,2) for our example above.

A background process has this variable, valid ranges, and the 
ability to measure performance for the app.


It then, in the background, perturbates t_i, say t_i_1(1.01, 1, 
2), monitors the performance impact, and stores the results.


This can be efficiently since the algorithm is quite simple, can 
be done without threading concerns(since the parameters are 
effectively immutable to app), and can run in the background just 
monitoring the app performance.


Using statistics, we can find out if the change had any 
significant effect(remember, we are doing this over the long 
haul, so any deviations will cancel out).


Eventually the program will optimize itself to run faster by 
choosing the values that best suit how the program is used during 
the optimization process(which can be done continually, and using 
better techniques than I have describe).


To accomplish this task easily, all one needs to do is have 
special variables usage


@Perf("Memory_Capacity")
if ($n*length >= $m*capacity)
expand($l*length);

The compiler then stores values(n,m,l) in a list, in this case we 
named it, along with the file position, etc. This is the only 
extra stuff that is done to a program. The special variable 
symbols $ was arbitrary, not necessarily desirable.


A BG thread is created that then does the optimization part. We 
might need to specify ranges for the values(the sample space for 
the algorithm, that could be done externally though).