Thread overview
enum on AA's and delegates debug info
Jun 30
Bert
Jul 01
Bert
Jul 03
Bert
June 30
an AA using an enum uses int as the base type rather than the enum member name.

enum X { A, B, C};
AA[X] x;

will show

[0]
[1]

instead of

[A]
[B]

It shouldn't be hard to get it to display the names through conversion.

Also,

delegates in an array do not show any value. This makes it difficult to know if they actually any value. Maybe you could just show the address of the delegate?
July 01

On 01/07/2019 01:27, Bert wrote:
> an AA using an enum uses int as the base type rather than the enum member name.
> 
> enum X { A, B, C};
> AA[X] x;
> 
> will show
> 
> [0]
> [1]
> 
> instead of
> 
> [A]
> [B]
> 

That's a long standing compiler bug: https://issues.dlang.org/show_bug.cgi?id=982, https://issues.dlang.org/show_bug.cgi?id=4372

> It shouldn't be hard to get it to display the names through conversion.
> 
> Also,
> 
> delegates in an array do not show any value. This makes it difficult to know if they actually any value. Maybe you could just show the address of the delegate?

It also doesn't show a delegate outside of an array. Implemented now for the next release.
July 01
On Monday, 1 July 2019 at 06:54:17 UTC, Rainer Schuetze wrote:
>
>
> On 01/07/2019 01:27, Bert wrote:
>> an AA using an enum uses int as the base type rather than the enum member name.
>> 
>> enum X { A, B, C};
>> AA[X] x;
>> 
>> will show
>> 
>> [0]
>> [1]
>> 
>> instead of
>> 
>> [A]
>> [B]
>> 
>
> That's a long standing compiler bug: https://issues.dlang.org/show_bug.cgi?id=982, https://issues.dlang.org/show_bug.cgi?id=4372
>

That is unfortunate. Is there not a way to get the proper type?

In the json file I have

      "deco" : "HE14test13AADFCQBj6SZv",
      "originalType" : "X[][A]",

Here A is the enum, it clearly knows it in the json... I wonder if that could be used to realize that the int can be converted to an A?

Visual D could simply try to convert any values to A and use the name if it passes, else fallback to the int.

>> It shouldn't be hard to get it to display the names through conversion.
>> 
>> Also,
>> 
>> delegates in an array do not show any value. This makes it difficult to know if they actually any value. Maybe you could just show the address of the delegate?
>
> It also doesn't show a delegate outside of an array. Implemented now for the next release.


Any ETA on it?
July 03

On 01/07/2019 22:39, Bert wrote:
> On Monday, 1 July 2019 at 06:54:17 UTC, Rainer Schuetze wrote:
>>
>>
>> On 01/07/2019 01:27, Bert wrote:
>>> an AA using an enum uses int as the base type rather than the enum member name.
>>>
>>> enum X { A, B, C};
>>> AA[X] x;
>>>
>>> will show
>>>
>>> [0]
>>> [1]
>>>
>>> instead of
>>>
>>> [A]
>>> [B]
>>>
>>
>> That's a long standing compiler bug: https://issues.dlang.org/show_bug.cgi?id=982, https://issues.dlang.org/show_bug.cgi?id=4372
>>
> 
> That is unfortunate. Is there not a way to get the proper type?
> 
> In the json file I have
> 
>       "deco" : "HE14test13AADFCQBj6SZv",
>       "originalType" : "X[][A]",
> 
> Here A is the enum, it clearly knows it in the json... I wonder if that could be used to realize that the int can be converted to an A?
> 
> Visual D could simply try to convert any values to A and use the name if it passes, else fallback to the int.

Probably simpler to fix in the compiler.

> 
>>> It shouldn't be hard to get it to display the names through conversion.
>>>
>>> Also,
>>>
>>> delegates in an array do not show any value. This makes it difficult to know if they actually any value. Maybe you could just show the address of the delegate?
>>
>> It also doesn't show a delegate outside of an array. Implemented now for the next release.
> 
> 
> Any ETA on it?

You can try a preliminary build from https://ci.appveyor.com/project/rainers/mago/build/artifacts by replacing MagoNatCC.dll in "<VS-Installation-Path>\Common7\Packages\Debugger".
July 03
On Wednesday, 3 July 2019 at 06:25:48 UTC, Rainer Schuetze wrote:
>
>
> On 01/07/2019 22:39, Bert wrote:
>> On Monday, 1 July 2019 at 06:54:17 UTC, Rainer Schuetze wrote:
>>>
>>>
>>> On 01/07/2019 01:27, Bert wrote:
>>>> an AA using an enum uses int as the base type rather than the enum member name.
>>>>
>>>> enum X { A, B, C};
>>>> AA[X] x;
>>>>
>>>> will show
>>>>
>>>> [0]
>>>> [1]
>>>>
>>>> instead of
>>>>
>>>> [A]
>>>> [B]
>>>>
>>>
>>> That's a long standing compiler bug: https://issues.dlang.org/show_bug.cgi?id=982, https://issues.dlang.org/show_bug.cgi?id=4372
>>>
>> 
>> That is unfortunate. Is there not a way to get the proper type?
>> 
>> In the json file I have
>> 
>>       "deco" : "HE14test13AADFCQBj6SZv",
>>       "originalType" : "X[][A]",
>> 
>> Here A is the enum, it clearly knows it in the json... I wonder if that could be used to realize that the int can be converted to an A?
>> 
>> Visual D could simply try to convert any values to A and use the name if it passes, else fallback to the int.
>
> Probably simpler to fix in the compiler.
>
>> 
>>>> It shouldn't be hard to get it to display the names through conversion.
>>>>
>>>> Also,
>>>>
>>>> delegates in an array do not show any value. This makes it difficult to know if they actually any value. Maybe you could just show the address of the delegate?
>>>
>>> It also doesn't show a delegate outside of an array. Implemented now for the next release.
>> 
>> 
>> Any ETA on it?
>
> You can try a preliminary build from https://ci.appveyor.com/project/rainers/mago/build/artifacts by replacing MagoNatCC.dll in "<VS-Installation-Path>\Common7\Packages\Debugger".

Thanks, it seems to be working. The only thing I really wish it could do not is display functions values.

I have tried to resolve the function values but I always get a symbol not found in the watch value.


It would be nice if the symbol could be searched for automatically or if they could be displayed in the autos/locals window as fields are. Obviously only parameterless methods and functions should be displayed(although maybe a dialog could pop up asking to input the arguments?).


The following code could be used as an example.

I'd like to get the value of Type. Only name shows up in the expansion list. Since I use property like functions heavily due to interfaces it ends up being problematic. This is usually not too bad since Visual D is now displaying fields properly and I usually back the properties with fields(although sometimes the method will modify the output).

It would be really cool to even call setters, I guess ideally a command window where one could execute parts of the program like repl would work well. C# and .net now have these things. I'm not sure how hard they are but it should be relatively straight forward? Just matching up symbols and then executing the code somehow(a parallel thread?)

Thanks for the update!


import std.stdio, std.traits;

struct ModelA
{
    // D only allows single inheritance, must use interfaces
    interface iAnimal
    {
        string Type();
		string Name();
        void Attack(iAnimal who);
        iFood LikesWhichFood();
    }

    interface iCat : iAnimal
    {
		void Meow();
    }

    interface iDog : iAnimal
    {
		void Bark();
    }
    interface iFood
    {

    }

    class Animal : iAnimal
    {
        void Attack(iAnimal who) { writeln(Name, " is attacking ", who.Name, "!"); }
        string Type() { return "Unknown Animal Type"; }
		override string Name() { return "Unknown Animal"; }
		iFood LikesWhichFood() { writeln("Food D Type: ", fullyQualifiedName!iFood); return null; }					
    }

    class Cat : Animal, iCat
    {
		string name = "Unknown Cat";
        override string Type() { return "Cat"; }		
		override string Name() { return name; }
        void Meow() { writeln("Meow!"); }
		this() { }
		this(string n) { name = n; }
    }

	class Dog : Animal, iDog
    {
		string name = "Unknown Dog";
        override string Type() { return "Dog"; }		
		override string Name() { return name; }
        void Bark() { writeln("Bark!"); }
		this() { }
		this(string n) { name = n; }
    }


    class Food : iFood
    {

    }
}


// Model B, It is "derived" from A, meaning Model B could, in theory, substitute for Model A as long as everything is designed correctly
// In this case we will create a ViewModel, a gui framework for ModelA. We actually cannot do this naturally in D since it does not support multiple inheritance.
struct ModelB
{	
    interface iAnimal : ModelA.iAnimal
    {
		// Provides a covariant return, which keeps the return values of ModelB in modelB.
		override iFood LikesWhichFood();
    }

    interface iCat : iAnimal, ModelA.iAnimal
    {

    }

    interface iDog : iAnimal, ModelA.iAnimal
    {

    }
    interface iFood : ModelA.iFood
    {
		void IsItTasty();
    }

    class Animal : ModelA.Animal, iAnimal
    {
		// This effectively isolates the cast that we would otherwise have to do everywhere in ModelB. We know ModelA.LikesWhichFood will return a ModelA.iFood type, but consistency will always provide us with an actually ModelB.iFood object, so the cast is always safe. [In effect, no instance of ModelA(or it's objects) diretly exists. ModelA is used only as a structural template. It is a sort of model instance.
		override iFood LikesWhichFood() { return cast(iFood)super.LikesWhichFood; }
    }

    class Cat : ModelA.Cat, iAnimal, iCat // We need to derive from Animal, not iAnimal, to provide proper ModelB implementation of Animal
    {
		//alias Attack = Animal.Attack;	// Required by D
		
		// In D, ModelA.Cat's implement is not provided as default, we have to reimplement everything. Or is Animal providing any implementation
        override string Type() { return super.Type; }		
		override string Name() { return super.Name; }
        override void Meow() { super.Meow; }
		void Attack(iAnimal who) { super.Attack(who); }
		override void Attack(ModelA.iAnimal who) { super.Attack(who); }
		override iFood LikesWhichFood() { writeln("Food D Type: ", fullyQualifiedName!iFood); return new Cabbage; }					
		this() { }
		this(string n) { name = n; }
		
    }

	class Dog : ModelA.Dog, iAnimal, iDog
    {
		alias Attack = Animal.Attack;	
        override string Type() { return super.Type; }		
		override string Name() { return super.Name; }
        override void Bark() { super.Bark; }
		override void Attack(ModelA.iAnimal who) { super.Attack(who); }						// Ideally we could just use covariance, ModelB.Dog.Attack will only take a ModelB.iAnimal, we will never insert a more generic ModelA.iAnimal, but the compiler forces us to be most general, even when we already are(since what happens in ModelB stays in ModelB).
		void Attack(iAnimal who) { Attack(cast(ModelA.iAnimal)who); }						// This is required use ModelB.iAnimal in ModelB(consistency)
		override iFood LikesWhichFood() { writeln("Food D Type: ", fullyQualifiedName!iFood); return new Donuts; }					
		this() { }
		this(string n) { name = n; }
    }


    class Food : iFood
    {
		void IsItTasty() { writeln("Unknown Food"); }
    }

	class Donuts : Food
	{
		override void IsItTasty() { writeln("YUK!"); }
	}

	class Cabbage : Food
	{
		override void IsItTasty() { writeln("YUM!"); }
	}
}
void main()
{

	{
		ModelA.iAnimal animal1 = new ModelA.Cat("Mittens");
		ModelA.iAnimal animal2 = new ModelA.Dog("Sparky");

		writeln(animal1.Name);
		writeln(animal2.Name);
		animal1.Attack(animal2);
		animal1.LikesWhichFood;
	}

	writeln("\n----------\n");

	{
		ModelB.iAnimal animal1 = new ModelB.Cat("Super Mittens");
		ModelB.iAnimal animal2 = new ModelB.Dog("Super Sparky");

		writeln(animal1.Name);
		writeln(animal2.Name);
		animal1.Attack(animal2);
		auto f = animal1.LikesWhichFood;
		f.IsItTasty; 		// Error: no property `IsItTasty` for type `Models.ModelA.iFood`. It should return a ModelB.iFood, we are inside ModelB, never any risk
		(cast(ModelB.iFood)f).IsItTasty;		// We can, of course, force it, but that is the rub, we don't have to, that is why we want to have a concept of a model, it tells the compiler that there is something more going on and it can reduce all this overhead. We can't even override this because of the contravariance rule.

	}

	writeln("\n----------\n");

	// This is the magic, ModelB is now substituted in Model A. It's basically still oop but our entire derived model is(or should be) used.
	// We can substitute the new model in all places where the old was used. This is the easy way to do ModelViewModel, we simply extend the model and add the view, no complex bridging, adapting, maintance, dependencies, etc.
	{
		ModelA.iAnimal animal1 = new ModelB.Cat("Super Mittens");
		ModelA.iAnimal animal2 = new ModelB.Dog("Super Sparky");

		writeln(animal1.Name);
		writeln(animal2.Name);
		animal1.Attack(animal2);
		animal1.LikesWhichFood;
		auto f = animal2.LikesWhichFood;
		//f.IsItTasty;	// This Error is ok, we are inside ModelA, ModelA would never use IsItTasty and it would be wrong to do so(it's only wrong because it should be impossible for ModelA to know about ModelB, else we create a dependency between models and really end up with one combined model rather than two separate models). But note that we could cast		
		(cast(ModelB.iFood)f).IsItTasty;		// We can, of course, force it though(only because we know for a fact we are actually dealing with a ModelB disugised as a ModelA, this is generally not the case), but this then shows a dependency. Note that it is exactly like the above model though... but there is a huge difference. In the first case it is afe, in this case it is not.. and the only difference is the model we are working in.
	}


    getchar();
}
July 04

On 03/07/2019 21:32, Bert wrote:
> Thanks, it seems to be working. The only thing I really wish it could do not is display functions values.
> 
> I have tried to resolve the function values but I always get a symbol not found in the watch value.
> 
> 
> It would be nice if the symbol could be searched for automatically or if they could be displayed in the autos/locals window as fields are. Obviously only parameterless methods and functions should be displayed(although maybe a dialog could pop up asking to input the arguments?).

Actually, the new DLL has improved support for evaluating parameterless functions, especially supporting all kind of return types. For example you can add watches "fully.qualified.function()" or "obj.member()" or even call a delegate "dg()", though it won't be executed after each step automatically due to possible side effects.

What doesn't yet work is virtual function dispatch, but that is probably your most common use case due to the ubiquitous use of interfaces. It should be possible to implement that, too...
July 05

On 04/07/2019 22:41, Rainer Schuetze wrote:
> 
> 
> On 03/07/2019 21:32, Bert wrote:
>> Thanks, it seems to be working. The only thing I really wish it could do not is display functions values.
>>
>> I have tried to resolve the function values but I always get a symbol not found in the watch value.
>>
>>
>> It would be nice if the symbol could be searched for automatically or if they could be displayed in the autos/locals window as fields are. Obviously only parameterless methods and functions should be displayed(although maybe a dialog could pop up asking to input the arguments?).
> 
> Actually, the new DLL has improved support for evaluating parameterless functions, especially supporting all kind of return types. For example you can add watches "fully.qualified.function()" or "obj.member()" or even call a delegate "dg()", though it won't be executed after each step automatically due to possible side effects.
> 
> What doesn't yet work is virtual function dispatch, but that is probably your most common use case due to the ubiquitous use of interfaces. It should be possible to implement that, too...
> 

Now virtual function call implemented plus a couple of fixes for delegates and function pointers. You can try the new preliminary build from https://ci.appveyor.com/project/rainers/mago/build/artifacts