« first day (1193 days earlier)      last day (1987 days later) » 

00:00
RELOAD!
[rubberduck-vba/Rubberduck] 1 opened issue. 1 closed issue. 2 issue comments.
@Mat'sMug Uhh okay.... those two sentences are contradictory.
00:23
@M.Doerner One issue I might have is this is only good for starting token but it won't really help me with ending token.
Given this evil code:

Option Explicit

Public _
Sub _
foo()

Debug.Print ""foo""

End _
Sub
#MarkdownFail
anyway - trying to get SubStmtContext with this code; from what I see in the code, the token.Stop.Line will yield correct result, but the token.Stop.Column will be 0 which is not correct. I cannot simply add the string's length because the token.Stop.Text includes the complete End _\r\n Sub
    Option Explicit

    Public _
        Sub _
    foo()

    Debug.Print ""foo""

    End _
        Sub
ah, there we go.
Incidentally charPositionInLine doesn't seem to be exposed to IToken
hence using Columnwhich seems to yield the expected result. Unfortunately, this works with the start of the token; so for Stop, it works with End but not the Sub, even though the Line will report it being on the same line where Sub of the End Sub is.
01:22
for now, I am solving this problem with this 3rd extension.
        public static int EndColumn(this IToken token)
        {
            if (token.Text.Contains(Environment.NewLine))
            {
                var splitStrings = token.Text.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
                var tokenOnLastLine = splitStrings[splitStrings.Length - 1];

                return tokenOnLastLine.Length;
            }
            else
            {
                return token.Column + token.Text.Length;
            }
I hope I'm not overextending things. :)
01:45
and I'm seeing problems with the context.Start.Line - in the evil code, it comes out as 4, the line where the Sub of Public Sub appears when I was expecting 3. Worse, the start.Start.Text only returns Public so I can't do the same trick I did w/ EndColumn. Going to stop for night and come back later with fresh eyes.
@this start returns the first IToken in the context
 
2 hours later…
03:40
Sure, that's fine. However, the issue is that the Public Sub is split over 2 lines, but the .Line returns me the line where Sub is on, while .Text only returns "Public". With the End Sub, .Text returns "End _\r\n Sub, so I can use that information to calculate the ending column. But I don't have any way to calculate the real starting line for the Public part of the Public Sub.
> Nice little working ribbon available now, along with the C# code. Save RibbonLibrary as an XLAM file and enable it; close and re-open EXCEL, then open the file BareRibbon.....xlsm.
[rubberduck-vba/Rubberduck] build for commit a54fcecd on unknown branch: AppVeyor build succeeded
 
1 hour later…
05:11
watched an Excel presentation last week. Presenter had his Personal.xlsb project expanded in VBE, where there was a little module called Hook visible. Astute attendees recognized that as CrackaJack
 
2 hours later…
07:14
@this I have been extrapolating the names from the online documentation, which has the names from the Java runtime. Column seems to be an exception in the name conversion.
@this Could you please post the complete string literal containing the code you use in your test? I think you might be overlooking an empty line at the start.
07:34
After having a look at GetSelection, I think that it actually has a bug: it does not take into account that tokens including line continuations are multiple lines long. So, it will have to use the new extension @this is writing for the end token column and also a new one for the row, which should also be wrong right now.
 
4 hours later…
11:06
@M.Doerner Ok, this is my [TestClass] public class SelectionExtensionsTests
internal visitor helepr:
        private class NodeVisitor<ParserRuleContext> : VBAParserBaseVisitor<ParserRuleContext>
        {
            private List<SubStmtContext> _contexts = new List<SubStmtContext>();

            public List<SubStmtContext> Contexts { get { return _contexts; } }

            public override ParserRuleContext VisitSubStmt([NotNull] SubStmtContext context)
            {
                _contexts.Add(context);
                return base.VisitSubStmt(context);
            }
        }
then the actual test method:
[TestMethod]
        [TestCategory("Grammar")]
        public void Token_Not_In_Selection_ZeroBased()
        {
            const string inputCode = @"
Option Explicit

Public _
    Sub _
foo()

Debug.Print ""foo""

    End _
  Sub : 'Lame comment!
";

            var vbe = MockVbeBuilder.BuildFromSingleStandardModule(inputCode, out var component);
            var state = MockParser.CreateAndParse(vbe.Object);
            var tree = state.GetParseTree(new QualifiedModuleName(component));
            var visitor = new NodeVisitor<SubStmtContext>();
Note that the inputCode has a empty line at the start -- the Option Explicit is on line 1 if we count from zero.
this "passes" but for wrong reasons.
this is my 2nd test method:
        [TestMethod]
        [TestCategory("Grammar")]
        public void Token_In_Selection_OneBased()
        {
            const string inputCode = @"
Option Explicit

Public _
    Sub _
foo()

Debug.Print ""foo""

    End _
  Sub : 'Lame comment!
";

            var vbe = MockVbeBuilder.BuildFromSingleStandardModule(inputCode, out var component);
            var state = MockParser.CreateAndParse(vbe.Object);
            var tree = state.GetParseTree(new QualifiedModuleName(component));
            var visitor = new NodeVisitor<SubStmtContext>();
the 2nd method fails though in the theory the selection should have contained the contents.
NB: I think I originally wrote selection to be new Selection(3, 0, 10, 7); I was probably verifying if selection was one-based, so it doesn't match the method name where the selection should be counting from zero-based index.
This test does not pass regardless, and this is all due to the Start not containing the real starting .Line which should be 4, counting from zero.
oh, and the extension method being tested. Note that it is likely still wrong because as I indicated the tests has never passed.
public static bool Contains(this ParserRuleContext context, Selection selection)
{
    return
       ((((selection.StartLine - 1) == context.Start.Line) && (selection.StartColumn - 1) <= context.Start.Column) || ((selection.StartLine - 1) < context.Start.Line))
    && ((((selection.EndLine - 1) == context.Stop.Line) && (selection.EndColumn - 1) >= (context.Stop.Column + context.Stop.Text.Length)) || (selection.EndLine - 1) > context.Stop.Line);
}
12:00
Hmm. Reading the documentation - it seems that Line are in fact one-based....
WTH. They use one-based for lines, but zero-based for columns.
3
I also see that our runtime files don't have the documentation --- they are just comments. In the github I linked, they have it in <summary> but ours are just comments. No wonder it didn't come up.
@this They're trying to keep the VBA users happy by providing some additional confusion and inconsistency.
No, not VBA
ANTLR
IDK maybe they have same people who wrote VBA writing ANTLR. :p
12:18
I was trackin'... the ANTLR folks are just trying to fit in with the VBA folks.
oh lol. look like so!
Nah, then columns would be one-bedroom as well.
must be pretty comfortable sleeping vertically.
How does one get new test added to the test explorer? I thought building would do it but it's just not coming up
@this on the ISS, sure!
@this Your visitor looks a bit strange. You just use it like a listener and return rubbish. It looks as if you want a VBAParserBaseVisitor<IEnumerable<ParserRuleContext>>. The way I see it, you would return the result of the base visitor with the context added in the override of VisitSubStmt.
12:31
IOW, I was supposed to override both VisitSubtStmt (already done) and also Visit() which I didn't.
Alternativly, you could wrote an extension akin to GetDecendent<T> that return all descendents of type T instead of just one.
right?
No
You never overwrite Visit.
when I execute .Visit(), I get null back. I think that's where I'm confused because I was expecting it'd return the result from the overridden VisitSubtStmt; it didn't, so I cam up with adding the results to a list.
There are two virtual functions in the base class of VBAParserBaseVisitor<Result> you can use to specify the default value to return from every node and the way how results get aggregated in VisitAllChildren.
The default for the default value is probably the default of the return type, which is null for all reference types.
12:40
OK; will study this more. I was also looking at this: dofactory.com/net/visitor-design-pattern
I will have to read up on visitors, when I am back from work.
but from the sample, it looks like it uses .Accept(), rather than calling .Visit() directly
Alright - I also ahve to go for now - thanks for the guidance!
That seems to be an the general visitor pattern, which is not the same as the Antlr visitor.
OK. I did notice earlier various parsers already have Accept() methods
13:20
Actually, from the pattern standpoint, the listener is a visitor.
14:20
Rename refactoring enhancement:
When the user has the following code and selection:
Sub F[oo]
End Sub
uh, that can't be legal
The [] is the selection....
oh wait, [ and ] denote the selection
missing parens
I thought subs didn't need parens.
Oh, that's the call.
...
so, yeah?
14:23
If the user didn't have a specific selection, we just leave the whole thing selected.
@Hosch250 my first iteration will expand the selection
but this is more low-level than where I am
@this First iteration on what?
extract method --- I just realized you're talking about rename might be different
Rename, which is definitely a different place.
my thought is that when user has made a partial selection, it should be expanded to the valid selection
that way it works as a hint to the user
14:30
Well, Extract is a completely different concern; this has no effect on it.
i'm not really talking about the extract / rename themselves. I'm talking about the UI aspect of selecting something to execute an action.
Uh, no.
We are definitely not going to be changing the user's selection.
Especially since each command has a different valid selection range.
in your example, they selected a part of the name. wouldn't it be really renaming of the full name?
@this I have a bit of a problem with that. as a user this is unintuitive weird behavior.
Yes, but it makes it easy for them to rename a specific part of a name.
Maybe someone had good naming, but always put "Foo" at the end of the name, or something. They could select Foo, use the command to open the Rename dialog, and hit Enter.
I always find making a selection in the code pane easier than in a dialog for some reason.
14:34
@Hosch250 I'm not clear what you're trying to do here. does any IDE do that?
@Mat'sMug VS.
It makes it so much easier than R#'s rename.
(And, it doesn't use a dialog at all.)
VS does the rename in-place - we're totally not there yet.
It doesn't matter, though, it is the same principle.
We have the information to pre-select the value, so why not? Or even make a setting for it (because options are always good).
there's currently 575 open issues, surely there's something more urgent/important than that to play with?
Maybe.
14:37
at least open one for that
After work.
They don't mind me chatting here, but they might object if I start "working" on it when I have other work to do.
I thought you were going to come up with a solution for
@Mat'sMug I kind of did, sort of.
@Hosch250 aye - I need to cut down on chat
At least, for variable assignment not used.
14:38
not getting enough done at work :)
@Hosch250 nice! is the concept generalizable?
Detecting code paths that will never be hit might be a little trickier; we have to keep track of the value of the variable, if possible.
I put it up on the wiki...
hmm, missed that
Other problems might need a different solution; not sure what else there is.
hmm, so kind of like we do parse tree inspections with a listener-per-inspection then?
I think so.
14:41
perhaps the common code-path tasks could be abstracted to a base class then
Perhaps.
I'd need to do a basic implementation to see if it will be feasible.
cool. start with "value not used" then :)
14:59
@Mat'sMug Potential partial fix for the RAM problem. A lot of our hashsets are only ever used in the resolver, right?
Let's pull those out into a different class, populate both classes just before the resolve, and clear the resolver-only only right after the resolve finishes.
And it doesn't have to be the resolver-only ones, either; it could be the primarily-resolver-except-for-1-or-2-inspections ones too, maybe.
most of them are reused in a number of inspections.. IDK, seems like it could be a lot of work for little benefit, compared to streamlining everything to a database
And if we ever need a C++ shim, I'd definitely talk to Loki and that other guy from MN (I forget his name :().
Wouldn't be too much work, actually.
we do need a shim
Well, those two could do it.
I know just enough C++ to get underfoot :P
I know just enough C++ to make an IDE crash :)
15:11
If you know that much, you must be pretty good. I'd expect an error message.
lol
right
Again, did someone run a memory profiler to pinpoint the issue?
I think value not used should rather be value never used, the same as variable not assigned should be variable not always assigned.
In general, there is no way to determine whether a branching condition is true at compile time.
Sometimes it is possible, but not in general.
15:32
@M.Doerner That's right.
Sometimes it is, If True Then.
And:
Dim val As Boolean
val = True
If val Then
Otherwise, not so much.
 
1 hour later…
16:42
@this @Mat'sMug Thank for your help Friday.
17:17
You're welcome! Just keep paying it forward. :)
I intend to do so by working on the issue tickets I've found.
 
1 hour later…
18:29
@this The following visitor should basically return what you wanted via its Visit function.
    public class CollectorVBAParserBaseVisitor<Result> : VBAParserBaseVisitor<IEnumerable<Result>>
    {
        protected override IEnumerable<Result> DefaultResult => new List<Result>();

        protected override IEnumerable<Result> AggregateResult(IEnumerable<Result> firstResult, IEnumerable<Result> secondResult)
        {
            return firstResult.Concat(secondResult);
        }
    }

    public class ModuleBodyElementCollectorVisitor : CollectorVBAParserBaseVisitor<VBAParser.ModuleBodyElementContext>
At least provided I have not missed something.
One could use something similar to determine all declarations definitly assigned inside a ModuleBodyElement.
Thank you, @M.Doerner I'll play with it when I'm free.
this definitely looks more generic than my silly internal class.
One thing bothers me though -- I'd think we should be overriding Visit<T> rather than VisitModuleBodyElement to make the visitor truly generic.... ?
There is no Visit<T>; there is only Visit taking an IParseTree.
I know. That's the part I don't understand.
because in the class, the code are highly repetitive - I'd think it'd benefit from being generic so we don't need to pick which VistXXX to override
18:45
Visit determins the underlying type of the IParseTree and calls the corresponding method.
Ah, I see.
You could write a visitor by hand passing in the IParseTree as dynamic and having overloads of Visit.
That is actually how the reference resolver is built.
The convenient thing about the Antlr visitor is that you do not have to write explicit visit methods for all types of contexts if you do not really need them.
As a further alternative, you could indeed write Visit<T> methods for all relevant types of contexts T and one for ParserRuleContext.
19:36
@IvenBach Don't limit yourself to those.
Not intending to. They are 01 or 02 difficulty. Enough to make me struggle.
I still don't think you are writing enough code. Write lots of "real" code and put it up on CR.
Then rewrite it and move on to something else.
I think you are mostly struggling with how large the project is at this point, and how limited in scope inspections are. You could write 30 inspections and still not have experience with a lot of things.
Write a small WPF app. You'd be surprised how much you learn when you have to do everything from top to bottom.
And don't worry about getting it right the first time. Make it work, make it right, make it fast.
I have an idea of what to do. It's just my 'better half' gets upset right now whenever I sit down to work on any coding.
Oh, OK. :P
Give her the time she needs; it'll save you money in the long run.
You've no idea.
19:43
Look at the cost of divorces...
I know my knowledge base, just working on RD, is making it tough. That's why I'm constantly toying with basics and getting a better feel in my down time at work.
I'm not worried about that. Wife already makes more that I do, I'd end up benefiting more than she would. Based on what we've been through since we've not split by now we never will.
She's more than a little difficult to handle, but worth it.
If we weren't making our project WCAG 2.0 compliant, I'd work on RD for the next two hours.
@IvenBach You might be surprised. I thought that about my parents, but they split this year when my dad went completely cuckoo.
My mom couldn't put up with his hallucinations any longer.
Before, he still knew who he was; he completely lost it this year.
He's mostly recovered, but he still has hallucinations and my mom isn't going to go through that again.
^ Sorry to hear about that. Mental illness is tough. I'd an uncle that never progressed past ~15-20 years of maturity.
Ouch.
I don't fault anyone for that.
19:48
Although, those are the best years to get stuck in :)
Not for me. So glad I'm past that phase pineapples go through. Never did affect me much thankfully.
 
1 hour later…
20:52
Duh check: What is constructor chaining?
Is it another tool to avoid duplication in code?
Foo(Type1 arg1, Type2 arg2) : this(arg1)
public MyClass(string foo) : this(foo, 42) { }

public MyClass(string foo, int bar)
{
     // do stuff
}
So, maybe you don't need both arguments, you can call Foo(arg1).
But if you want to use both, constructor 1 handles arg1 and ctor 2 handles arg2.
It is also used in the case Mat gives, particularly when you have a constant value that isn't a compile-time constant so you can't use a default argument.
@Hosch250 Where's the ctor1? this(arg1) would be the other constructor?
Yeah, ctor 1 would be like: Foo(Type1 arg1)
20:55
I'm going through csharp.2000things.com/2011/04/02/… and my kneejerk reaction was to refactor it and simplify it to...
public class Program
{
	public static void Main()
	{
		Dog foo = new Dog("bar");
		Console.WriteLine(foo);
	}

	public class Dog
	{
		public string Name { get; set; }
		public int Age { get; set; }
		public string Motto { get; set; }

		public Dog(string Name) : this(Name, 1, "Happy") {}

		public Dog(string name, int age) : this( name, age, "Happy") {}

		public Dog(string Name, int Age, string Motto)
		{
			this.Name = Name;
			this.Age = Age;
			this.Motto = Motto;
		}
		public override string ToString()
@IvenBach Yup.
I'm understanding some principles then.
Except you missed one ctor.
@Hosch250 public Dog(string Name, string Motto) : this( Name, 1, Motto) {} Was the implied missing option?
Yup.
class Program
{
    static void Main(string[] args)
    {
        new Foo(9);
    }
}

public class Foo
{
    public Foo()
    {
        Console.WriteLine("Hi 1");
    }
    public Foo(int i) : this()
    {
        Console.WriteLine("Hi 2");
    }
}
Guess what that prints.
20:59
I try not to do What-If since YAGNI but would there be any benefit to further abstracting 1 and Happy to private constants of defaultAge and defaultMotto?
@Hosch250 Give my mind a minute to process
Without testing anything I'd say Hi 1 and then Hi 2 based on order.
@IvenBach Maybe. It really depends on the situation.
@IvenBach Yup.
Now, why is it important to know that?
Order of operations and when you want something to occur.
@IvenBach Well, sort of.
Would it deal with initialization or readonly fields?
Ctors change state, especially for readonly variables and get-only properties. Sometimes you'll do some calculations in the ctor that use these properties, and you need to know whether they are assigned.
@IvenBach That is part of it.
@IvenBach Based on what order?
21:05
Could be a possible collision of a backing field already initialized in one constructor and then it's tried to be initialized again, causing an error.
Testing that ^. One sec.
not an error - the object isn't constructed yet
so re-assignment is fine
Works:
public class Foo
{
    private readonly int s;

    public Foo()
    {
        s = -1;
        Console.WriteLine(s);
    }
    public Foo(int i) : this()
    {
        s = i;
        Console.WriteLine(s);
    }
}
@Mat'sMug It's only fully constructed once the first called ctor is done running? I lack proper vocab to describe.
it's fully constructed when the caller gets the new instance they asked for
No, it is fully constructed when the last ctor in the initialization runs.
21:08
@Mat'sMug & @Hosch250: Inside looking out, or outside looking in?
:this(foo) and :base(foo) run before { ... }
@PieterGeerkens Both :P
Outside looking in "sees" a slightly later time than inside looking out does
@Mat'sMug That's helpful. Greatly so.
@IvenBach and this is why you should never make virtual member calls in a constructor
21:10
@PieterGeerkens Actually, probably not really.
^^
@Mat'sMug @puzzlepiece87 @FreeMan When you get around to C#ing this will make things a lot easier with derived classes.
@Mat'sMug Because they can be overridden in the constructors? I'm not following.
@IvenBach No, because things might not be done initializing.
And the base class runs before the descendant class.
Hmmm.
@Hosch250 depends; ctor overloads chained to base will run first
I think I understand it.
basically you can't be 100% sure that there won't ever be a derived class that overrides the virtual method you're calling
virtual methods are meant to be overridden; they wouldn't be virtual otherwise
21:17
Actually, calling virtual methods in a constructor in C# is a lot less problematic then in C++.
@Mat'sMug Like how?
At least, in C# the object always has the derived type from the start.
public Foo() : this(42) { /* nevermind @Hosch250, this runs after the base ctor too  */ }
public Foo(int bar) : base(bar) { }
lol, I realized as I was typing it up
@Mat'sMug Yep. The base always runs first.
It starts at the base and walks back up the chain.
it's actually easier to visualize when you start at the ctor overload you're calling and follow the execution path
* knowing that :this and :base will execute before the body of that ctor
21:21
@IvenBach Also, even if the virtual call doesn't crash, there is a good chance there will be unexpected data used:
    class Program
    {
        static void Main(string[] args)
        {
            new Foo1(9);
        }
    }

    public abstract class Foo
    {
        protected Foo(int i)
        {
            Console.WriteLine("base");
            Fizz();
        }

        public abstract void Fizz();
    }

    public class Foo1 : Foo
    {
        private int _i = -1;

        public Foo1() : base(0)
        {
            _i = 10;
            Console.WriteLine("empty");
        }

        public Foo1(int i) : this()
Now that you know how the ctors run, see if you can figure out the output without running that.
public class Program
{
	public static void Main()
	{
		Foo foo = new Foo(5);
	}

	public class Foo : Bar
	{
		private readonly int s;

		public Foo()
		{
			s = -1;
			Console.WriteLine(s);
		}
		public Foo(int i) : this()
		{
			DukheadedMistake();
			s = i;
			Console.WriteLine(s);
		}

		public override void DukheadedMistake()
		{
			Console.WriteLine("Really really messed up.");
		}
	}

	public class Bar
	{
		public Bar()
		{
			DukheadedMistake();
		}
		public virtual void DukheadedMistake()
Because DukheadedMistake is overridden that's the reason Really really messed up. is printed twice?
@IvenBach: Wouldn't it would be trickier if Fizz() was virtual instead of abstract?
Yup.
@Hosch250 Going through this right now.
Stop reusing objects. Treat objects like condoms and you'll do great. — Mat's Mug 6 secs ago
2
pretty sure that image is going to ..stick.
21:30
Btw, in C++ you would have seen Messed up.
@Mat'sMug He probably reuses those too.
aaaaand on that note, TTQW
@Hosch250 Foo(int i) called first outputting base, and Fizz outputting 0. Then Foo1() outputting empty. Then Foo1(int i) outputting 1 arg.
@IvenBach Close, but no cigar.
When do you think field/property initializers run?
The multiplicity in beyond me at present.
I don't have any idea when they run.
21:36
Before the ctors.
Fizz() prints -1 in that case.
I'm having to use a web compiler since I can't use VS while at work.
Typing up what I understand as an example before I say something wrong.
@Hosch250 They run so that my example below makes sense.
public class Program
{
	public static void Main()
	{
		Foo noParams = new Foo();
		noParams.writeOut();

		Foo barParam = new Foo(99);
		barParam.writeOut();

		Foo buzzParam = new Foo("beeble");
		buzzParam.writeOut();

		Foo barbuzzParam = new Foo(55, "bobble");
		barbuzzParam.writeOut();
	}

	public class Foo
	{
		public int bar = 5;
		public string buzz = "BuzzBar";

		public Foo(int bar)
		{
			this.bar = bar; //writes over 5
		}

		public Foo(string buzz)
		{
			this.buzz = buzz; //writes over "BuzzBar"
@IvenBach Not sure what that is supposed to mean..
If field/property initializers didn't run before the constructor than whatever was in the initializer would be the value irregardless of what the constructor parameter takes in.
Yep.
And that is why my example prints -1.
They will always run before you can access that object.
My cave-man brain can only have coherence come out so fast.
I'd seen that behavior before but didn't know what to call it. #TIL
Duh check: field & property initializers have the same precedence IE treated like ( * , / ) and not ( *, + where multiplication comes before summation). They proceed in a top down manner too.
21:52
Yes.
Except it doesn't matter because you can't reference a non-static member in the initializer.
So the order they are executed in doesn't matter.
And top-down, I don't know, and I don't care.
Thanks. I'm trying really hard to properly understand things properly.
    public class Foo1
    {
        public Foo1()
        {
            i = new Bar();
            Console.WriteLine(I == null);
        }

        private static Bar i;
        private Bar I { get; } = i;
    }

    public class Bar{}
That works only because i is static.
Guess what it prints.
TTQW.
@Hosch250 The -1 is printed because Fizz() is called because of the constructor chaining and before _i is assigned anywhere leaving the initialized value.
@Hosch250 Working on thinking this through now.
@Mat'sMug Referring to Parent might result in a leak.
@Mat'sMug pretty sure Randall's original draft used condom in place of paper towel.
hi @2EZ4RTZ
22:08
How did you know
avatar animation in the sidebar
Huh I thought it took a message to join :P
I was on my way to try and get calc help on math SE
Btw rubberducks and the way to live
@2EZ4RTZ just rep
hi @KolosovPetro
@ThunderFrame Huh
@Hosch250 False is my guess because static means its always accessible.
:39945597 	public class Foo1
    	{
    		public Foo1()
    		{

    			i = new Bar();
    			this.I = i;
    			Console.WriteLine(I == null);
    		}

    		private static Bar i;
    		private Bar I { get; set; }
    	}

    	public class Bar{}
22:14
@2EZ4RTZ you need reputation on SE (20 IIRC). Stops new users spamming chat.
Had to edit it since I'm not using C#6. Makes more sense seeing it this way. Assuming I edited it correctly.
@Mat'sMug If I make my StorageRoot class disposable, that will make it differ from the internal implementation, but IMO that'd be worth it. I'd just call the Close method inside the Dispose() implementation? There's nothing else to dispose of, as such....
@ThunderFrame I have more then that (over 2k network)
I just did a memory profiling session and now I think even more, that the DeclarationFinder is not the real problem: it uses 6MB of memory.
That is, in my test project with about 140 classes and modules in total.
Most memory we are holding is actually unmanaged.
I had a managed memory consumption of 182MB and an unmanaged one of 230MB.
22:44
@M.Doerner huh,...wtf is it then?
@Mat'sMug button icons :-/
230MB of 16x16 bitmaps???
The largest block of managed resources is the RubberduckParserState because it is holding about 20 MB of module states, 16 MB of projects, 7 MB of strings and some other stuff. Another part are the 25 MB of module contexts we are holding in memory in my test case. Ninject consumed 17 MB.
The profiler did not provide any information for the unmanaged part or I simply did not find it.
That would be the RCW's?
22:52
@this will want to see that
Maybe I should have a look at a smaller project tomorrow and also take a snapshot before requesting the first parse.
Btw, I used dotMemory.
TTGTB
be forewarned; never had used memory profiler.
'night!
But it really smells - we shouldn't be duplicating so much what is already in memory by VBIDE - so the first question should be -- are those from VBA itself, without loading RD?
think it'll help to have a baseline of w/o RD then w/ RD to understand what effect there are.
I've no idea
22:57
anyway, something to do for tomorrow. Thanks for looking & 'night, @M.Doerner
But moving lookups to a db would have marginal effect on RAM
yep, sounds like.
my impression were off because from what I was seeing, it was noticably slowing when using insepections 'n' stuff
incidentally it's also where it's crash-prone
Inspections run whether you view the results or not, unless explicitly disabled
hence my impressions .... what user see isn't what a programmer does. :)
bbl
For all we know half of that unmanaged RAM is consumed by Excel itself
23:20
With a shim launching our own AppDomain I think we'd get a clearer picture of RD's actual unmanaged footprint
23:47
@this I'm not sure what we might be "duplicating". We're keeping references to interop types that wrap COM objects exposed by the VBIDE API, is all.
Hmm we load all referenced type libraries through Win32 to extract their members though... Stupid question: are we unloading them?
@IvenBach Uh, no.
2 hours ago, by Hosch250
Before the ctors.
i is set to null before the ctor runs. Then I is set to i.
for the record, mixing static and instance fields and constructor initialization messes with the reader's mind. don't do that without a very very very good reason.
@Mat'sMug Not in production code.
In learning code, definitely experiment with it.
Oh, absolutely!
So wait a sec, that means { get; } = foo; is only legal/meaningful in static context?
I don't like that syntax, it's hard to grok. Maybe just because I haven't been using 6.0 for long, but it's definitely not intuitive
@Mat'sMug My blind shot-in-dark was that for each wrapped type, a RCW get created, and thus get duplicated if we have multiple references. IDKTBH. This is me just guessing and so far, my guesses has been off the mark.
23:59
@this possible, but not much we can do about it
s/type/object/ btw ;-)

« first day (1193 days earlier)      last day (1987 days later) »