Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
abraham linksys
Sep 6, 2010

:darksouls:

Space Whale posted:

So if I have the object

var o = {0: 1, 1:2, dick: "butt"};

would foreach iterate over 1 and 2 but not dick?

please don't set non-numeric properties on an array that's some zalgo poo poo where i don't even know what the gently caress happens

look just read the description in this for an understanding of what an array is in javascript before continuing okay https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array

and in general just please, like, read literally any book about javascript? you're clearly not an idiot but you're just not familiar with the basics of the language and trying to apply what you know in some other language to js, which is going to lead to lots of code that """works""" but is extremely bad (see: your lack of understanding of "this"). if you can't articulate the different between an object and an array you should just brush up with some very light reading :)

abraham linksys fucked around with this message at 01:05 on Aug 18, 2016

Adbot
ADBOT LOVES YOU

abraham linksys
Sep 6, 2010

:darksouls:
hell eloquent javascript is $8 right now in https://www.humblebundle.com/books/joy-of-coding-book-bundle just grab that, that's a pretty beloved book

MononcQc
May 29, 2007

yeah plus you'll be stuck with my erlang book in there just do it

Space Whale
Nov 6, 2014

abraham linksys posted:

please don't set non-numeric properties on an array that's some zalgo poo poo where i don't even know what the gently caress happens

I didn't. :mad:

edit: Right now I'm trying to make a thing work, I'll go on a refactor spree later (time permitting, not up to me!) and I ended up with an array of array of... things which had 0 through n numeric properties and also two name properties.

I did NOT choose this.

this is just scope, right? Hence self=this bla bla bla self.someglobalfuckyou.

Space Whale fucked around with this message at 01:24 on Aug 18, 2016

abraham linksys
Sep 6, 2010

:darksouls:
the super easy refactor i'd recommend for those things would be to just put the array into another key

code:
// instead of
var thing = [1,2,3];
thing.namedProp1 = 'foo';
thing.namedProp2 = 'bar';

// do this
var thing = {
  items: [1,2,3],
  namedProp1: 'foo',
  namedProp2: 'bar',
};
you're right that "this" is a reference to the current scope, but the way you keep calling items on a scope "global" make me think you're not really grokking scope. that's a topic i do not particularly want to try to explain in a yospos post

Luigi Thirty
Apr 30, 2006

Emergency confection port.

hooray! i can traverse a FAT12 cluster chain in 68k assembly and read a complete file into memory :toot:

Space Whale
Nov 6, 2014

abraham linksys posted:

the super easy refactor i'd recommend for those things would be to just put the array into another key

code:
// instead of
var thing = [1,2,3];
thing.namedProp1 = 'foo';
thing.namedProp2 = 'bar';

// do this
var thing = {
  items: [1,2,3],
  namedProp1: 'foo',
  namedProp2: 'bar',
};
you're right that "this" is a reference to the current scope, but the way you keep calling items on a scope "global" make me think you're not really grokking scope. that's a topic i do not particularly want to try to explain in a yospos post

My architect calls them globals. I'm reasonably sure they are; there's a chance he's full of poo but this app is made very badly. I'll go read about scope I guess.

That said, if I have a thing with 1 through n, and two non numeric properties, can I just delete the non numeric properties from the object? Otherwise how would I move 1->n into (LETS GO DEEPER!) another property which is itself a normal indexable array?

skimothy milkerson
Nov 19, 2006

abraham linksys posted:

hell eloquent javascript is $8 right now in https://www.humblebundle.com/books/joy-of-coding-book-bundle just grab that, that's a pretty beloved book

:aaaaa: take my money!

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder

Space Whale posted:

My architect calls them globals. I'm reasonably sure they are; there's a chance he's full of poo but this app is made very badly. I'll go read about scope I guess.

That said, if I have a thing with 1 through n, and two non numeric properties, can I just delete the non numeric properties from the object? Otherwise how would I move 1->n into (LETS GO DEEPER!) another property which is itself a normal indexable array?

I don't actually know if this is true, but I could imagine that in the top level scope, 'this' refers to the Window object. In that case, you could effectively treat members of 'this' as globals, but only when you're at the top level scope.

has your architect never defined a method on an object?

e: hey i was right. i think i must have just known this and forgot.

code:
> this
Window

> var butt = {}
> butt.fart = "toot"
> butt.poop = function(){ console.log(this.fart) }
> butt.poop()
toot

DONT THREAD ON ME fucked around with this message at 01:56 on Aug 18, 2016

abraham linksys
Sep 6, 2010

:darksouls:

MALE SHOEGAZE posted:

I don't actually know if this is true, but I could imagine that in the top level scope, 'this' refers to the Window object. In that case, you could effectively treat members of 'this' as globals, but only when you're at the top level scope.

the one caveat is that this is only true when you're not in strict mode! but yeah in a lot of bad loose-mode js code people use this when they should be using window, which can lead to extremely fun times when someone decides to give Function.prototype.bind() a shot

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder
Javascript really is the funnest of the p-langs

abraham linksys
Sep 6, 2010

:darksouls:
javascript is fun cuz you'll have spent enough time with it that you'll finally think you know everything there is to know, then you go to use Array.prototype.reverse and see it returns an array and assume it returns a new copy, only to find out 30 minutes of debugging later that, nah, it in fact mutates the array but also returns a reference to it, and then you'll want to die

that's what "fun" means right

Stringent
Dec 22, 2004


image text goes here
wait, why would you assume that? isn't mutating and returning a reference SOP for plangs?

JewKiller 3000
Nov 28, 2006

by Lowtax
half of the functions in the javascript standard library mutate stuff and the other half return a new copy. each individual function is part of the half you think it's not in

abraham linksys
Sep 6, 2010

:darksouls:

Stringent posted:

wait, why would you assume that? isn't mutating and returning a reference SOP for plangs?

no?

code:
Python 2.7.10 (default, Oct 23 2015, 19:19:21)
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

>>> arr = [1, 2, 3]
>>> ret = arr.reverse()  # mutates arr
>>> print ret
None
>>> arr
[3, 2, 1]

>>> arr = [1, 2, 3]
>>> reversed(arr)  # does not mutate arr
<listreverseiterator object at 0x101763610>
>>> [x for x in reversed(arr)]
[3, 2, 1]
>>> arr
[1, 2, 3]
certain third party js apis do it to allow method chaining (such as moment, which as i mentioned is a known Bad API that is getting a frozen/immutable variant) but it's a lovely confusing antipattern. either mutate the reference you're passed and return null or return a reference, don't do both

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder
it's me, i'm the bad dev who writes method chaining apis.

in my defense, my method chaining apis always return a value and never mutate, but that's because performance, lol

abraham linksys
Sep 6, 2010

:darksouls:
as long as you're really explicit about method-chaining existing in your api it's probably fine. i mean there's stuff like lodash's _.chain that is perfectly fine, it's as explicit as possible about what's happening.

(then there's stuff like lodash's _.reverse which just calls the native reverse and has the same semantics and it makes me want to die)

abraham linksys
Sep 6, 2010

:darksouls:
man even everyone's least favorite language ruby has an awesome and consistent convention for methods that mutate the original value

code:
irb(main):001:0> a = [1,2,3]
=> [1, 2, 3]
irb(main):002:0> a.reverse
=> [3, 2, 1]
irb(main):003:0> a
=> [1, 2, 3]
irb(main):004:0> a.reverse!
=> [3, 2, 1]
irb(main):005:0> a
=> [3, 2, 1]

Corla Plankun
May 8, 2007

improve the lives of everyone

abraham linksys posted:

code:
irb(main):002:0> a.reverse
irb(main):004:0> a.reverse!

the little touches like that are what really sold me on that language when i had to learn it for an internship a few years ago

it is so nice to write in for little stuff!

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder
it's not really adhered to, tbh. it kinda doesnt really make sense most of the time

e: bangs in ruby, i mean

DONT THREAD ON ME fucked around with this message at 02:43 on Aug 18, 2016

Space Whale
Nov 6, 2014
So if i have numerics and non numerics in the same thingy wtf do I do

Weekend Bridges
Apr 8, 2015

by Smythe

abraham linksys posted:

man even everyone's least favorite language ruby has an awesome and consistent convention for methods that mutate the original value

destructive methods don't consistently have a bang and a bang doesn't consistently mean it's destructive

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder

Weekend Bridges posted:

o
destructive methods don't consistently have a bang and a bang doesn't consistently mean it's destructive

yeah the whole concept of mutability in ruby is hosed and then people start to overload the bang to mean like, that it mutates global state or w/e, and next thing you know you're confused

my only real 'wow i totally misunderstood how the programming language works and it made it into production' moment was this:
code:
# ruby entrails

# Foo is an ORM model
f = Foo.find('whatever') # get Foo from the db

# copy farts from f, because i want to do things with farts
farts = f.farts 

# many lines later, while doing things with farts
farts << 'A Fart' # append a fart to farts

# later
f.save! # saves the new state of f to the database

Bloody
Mar 3, 2013

Star War Sex Parrot posted:

RULE 5: There shall be no use of dynamic memory allocation after task initialization.

http://lars-lab.jpl.nasa.gov/JPL_Coding_Standard_C.pdf

this is a great read, why havent i read it before

Bloody
Mar 3, 2013

except the section on assertions is full of some kinda gross lookin poo poo

VikingofRock
Aug 24, 2008




Mutating and returning None instead of mutating and returning a reference caught me off guard all the time when I first started using Python. To this day I'll still do

Python code:
flipped_rows = [row.reverse() for row in rows]
and I'm always surprised when I get a list full of Nones as a result. I think in Effective C++ Scott Meyers recommends returning a reference from mutating methods in order to allow for method chaining, and reading that book was probably my first attempt to get "good" at programming. Also the C++ STL does it a lot IIRC. So when I started programming outside of C++ I was shocked when not everyone did that.

abraham linksys
Sep 6, 2010

:darksouls:

MALE SHOEGAZE posted:

yeah the whole concept of mutability in ruby is hosed and then people start to overload the bang to mean like, that it mutates global state or w/e, and next thing you know you're confused

okay well fine it's a good idea in theory (i've written very little ruby)

i wish there was a similar convention, or at least attempt at one, in js, something like Array.prototype.reverseMutate() or smth

Space Whale posted:

So if i have numerics and non numerics in the same thingy wtf do I do

this is still a weird problem to me. like, if you have an object, you can use "numbers" as keys, but those "numbers" are just getting cast to strings on both the set and get ends. if you have an array, you can use numbers for indices and strings for keys to non-indexed items, but then poo poo just gets insanely weird in a wat sorta way. the only sane way to handle this in javascript is to, like, i said, use an object that contains an array as one of its values.

so like... what on earth is this object you're consuming that is an array that has additional properties set on it? can you just refactor whatever code is creating it?

abraham linksys
Sep 6, 2010

:darksouls:

VikingofRock posted:

I think in Effective C++ Scott Meyers recommends returning a reference from mutating methods in order to allow for method chaining, and reading that book was probably my first attempt to get "good" at programming. Also the C++ STL does it a lot IIRC. So when I started programming outside of C++ I was shocked when not everyone did that.

my assumption here is that you would very rarely expect methods in C++ to return a new data structure, given the usual use cases of C++, so that makes sense to me. to anyone coming from a functional programming background, the very idea of a regular ol' function mutating a data structure that it's passed in is sorta blasphemous.

javascript, being javascript and drawing people from all walks of life, often attracts people on both sides of spectrum. personally i just like it when methods are extremely clear that they are mutating what they're passed, and the most obvious signal of that is that they don't return anything, and i draw that from python (another good example of this is sorted(foo) vs foo.sort()).

honestly i wouldn't be that annoyed about reverse() in JS except for, as previously mentioned, the completely arbitrary randomness of what methods mutate and what don't. at least with python you have the convention of "global functions are gonna return a new thing while methods are going to mutate it"

Space Whale
Nov 6, 2014

abraham linksys posted:

so like... what on earth is this object you're consuming that is an array that has additional properties set on it? can you just refactor whatever code is creating it?

Yes.

Will $shockinglyBigISP pay me/my team to do that?

https://www.youtube.com/watch?v=YpddaZB9bcI

abraham linksys
Sep 6, 2010

:darksouls:
welp you could do this I guess

code:
var shittyArray = [1,2,3];
shittyArray.one = 'foo';
shittyArray.two = 'bar';

var betterObject = {
  items: shittyArray.slice(),  // creates a new array with only numerically-indexed items
  one: shittyArray.one,
  two: shittyArray.two,
};
but I can't guarantee that works because of the aforementioned wat-like behavior of arrays with extra keys attached, ymmv

fritz
Jul 26, 2003

abraham linksys posted:

my assumption here is that you would very rarely expect methods in C++ to return a new data structure, given the usual use cases of C++, so that makes sense to me. to anyone coming from a functional programming background, the very idea of a regular ol' function mutating a data structure that it's passed in is sorta blasphemous.

my c++ reckons would be that it's perfectly fine to return a new data structure in c++ b/c you can let the compiler do the return-value optimization https://en.wikipedia.org/wiki/Return_value_optimization

fritz
Jul 26, 2003

well i guess thats not quite the same thing but w/ever

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder

abraham linksys posted:

if you have an array, you can use numbers for indices and strings for keys to non-indexed items,
so like... what on earth is this object you're consuming that is an array that has additional properties set on it? can you just refactor whatever code is creating it?

i didn't understand what you guys were talking about but it suddenly just clicked and that is horrifying. i'd never really realized that about Arrays.

Space Whale
Nov 6, 2014

abraham linksys posted:

welp you could do this I guess

code:
var shittyArray = [1,2,3];
shittyArray.one = 'foo';
shittyArray.two = 'bar';

var betterObject = {
  items: shittyArray.slice(),  // creates a new array with only numerically-indexed items
  one: shittyArray.one,
  two: shittyArray.two,
};
but I can't guarantee that works because of the aforementioned wat-like behavior of arrays with extra keys attached, ymmv

What scared me is how easily I was able to find questions online about this and canned idioms to handle it.

abraham linksys
Sep 6, 2010

:darksouls:

MALE SHOEGAZE posted:

i didn't understand what you guys were talking about but it suddenly just clicked and that is horrifying. i'd never really realized that about Arrays.

it's real good times. i keep referencing the "wat-like" behavior because i've definitely seen code samples where this can gently caress poo poo up badly, like the original wat talk might actually have this in there (i should just rewatch it). i want to say you can get an array into a state where length returns the incorrect value, or something equally strange?

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av
hahaha what the gently caress is wrong with me I actually did it. so I took this extremely trivial sample from the Windows Scripting documentation:

JavaScript code:
var fso = new ActiveXObject("Scripting.FileSystemObject");
var a = fso.CreateTextFile("c:\\testfile.txt", true);
a.WriteLine("This is a test.");
a.Close();
and rewrote it in C. kill me now:

C++ code:
// I do, in fact, know what these two defines do, I don't cargo-cult them
#define WIN32_LEAN_AND_MEAN
#define STRICT

// The helper macros like IUnknown_QueryInterface aren't defined unless we
// define this first. Wow, so Microsoft does care about namespace pollution
// after all!
#define COBJMACROS

#include <stdlib.h>

#include <windows.h>
#include <objbase.h>

int main()
{
	// Initialize COM, give ourselves a "single threaded apartment". Apartments
	// are COM's equivalent of .NET application domains, kinda. Objects belong
	// to the apartment in which they were created, and to call them from a
	// different apartment, you have to do it with RPC, like they were in a
	// separate process (unless the objects are marked as free-threaded, i.e.
	// they can do their own thread safety, thank you very much). A STA (single
	// threaded apartment) is the simplest kind of apartment, which belongs to
	// the thread it was created in. This is fine
	HRESULT hr = CoInitialize(NULL);

	if (FAILED(hr))
		return EXIT_FAILURE;

	CLSID clsid;

	// I'll chain error checks instead of nesting them, otherwise the nesting
	// depth would get ridiculous fast
	if (SUCCEEDED(hr))
		// COM classes are identified by user-unfriendly CLSIDs. CLSIDs are
		// fine for C, because almost always we have a constant somewhere in
		// some platform or application header that gives the CLSID a symbolic
		// name. COM has runtime friendly names too, though, two kinds of them
		// in fact: monikers, i.e. URNs/URIs (in fact, monikers predate them),
		// which identify existing objects (an object serialized to a file,
		// like, say, a Word document, or a currently running object, which is
		// e.g. how you connect through COM to services like WMI), and progids,
		// which identify classes. "Scripting.FileSystemObject" is a progid,
		// and CLSIDFromProgID looks it up in the registry to find the
		// corresponding CLSID. When you "register a COM/OLE component", the
		// progid-to-CLSID entries are the most common kind of information
		// that gets registered. Progids have a structured but kind of lovely
		// syntax: <application>.<class>[.<version>]. I like XPCOM's syntax
		// a lot more (XPCOM is Mozilla's implementation of COM, used
		// internally by Firefox, Thunderbird, etc.). I forget the specifics,
		// I just remember it's much nicer, better thought out.
		// Almost forgot: CLSIDs are, of course, UUIDs
		hr = CLSIDFromProgID(OLESTR("Scripting.FileSystemObject"), &clsid);

	// This is equivalent to the script variable of the same name
	IDispatch *fso = NULL;

	if (SUCCEEDED(hr))
		// CoCreateInstance loads the class's implementation (loads a DLL for
		// "in-process servers", or it runs a program for "out-of-process
		// servers". We specify CLSCTX_ALL to tell COM we don't care where the
		// code comes from), gets the class factory for the class identified by
		// the provided CLSID, and uses it to construct an object. COM has no
		// constructors, objects are always created in a default state. In
		// fact, Scripting.FileSystemObject is in turn a non-standard class
		// factory: some of its methods allocate objects and initialize them
		// with user-defined parameters
		hr = CoCreateInstance(&clsid, NULL, CLSCTX_ALL, &IID_IDispatch, &fso);

	// fso is a so-called "late-bound" object. It means that we don't have type
	// information at compile time - above all, we don't have a definition for
	// its interfaces, so we can't call its methods with a combination of vtable
	// accesses and function calls (all "trivial" operations that map directly
	// to machine instructions, and as such supported by C). We'll have to do
	// all method invocations dynamically, which is, as you can guess, a massive
	// pain in the rear end and several other less-than-honorable parts of the human
	// anatomy

	// Michael Kaplan (RIP ;_;) said you should never use the thread locale, but
	// I say what the hell did he know?
	LCID lcid = GetThreadLocale();

	// Late binding/dynamic invocation revolves around the IDispatch interface,
	// and is done in two phases: looking up named methods and arguments, and
	// invocation (property getters/setters are just special cases of method
	// invocations). This turned out to be a bad idea for truly dynamic
	// languages, where you may want to delete methods and properties. In OLE,
	// you'll leak them because name-to-dispid resolution is, like IID-to-
	// interface resolution, supposed to be stable, so you have to keep the
	// deleted names around in case someone cached the resolved dispids. By the
	// way, OLE (AKA Automation) means Object Linking and Embedding and it's an
	// application of COM aimed at standardizing components and object-oriented
	// RPC. Very technically speaking, OLE is not an application of COM, OLE 2
	// is. The original OLE used DDE, but that's a story for another day
	DISPID dispid;

	if (SUCCEEDED(hr))
	{
		// So anyway, here we look up the dispid of fso.CreateTextFile. OLESTR
		// is a macro that pastes an L in front of the string literal, to make
		// it a wide string literal. The Windows SDK demands that the compiler
		// uses 16-bit wide characters, which used to be an issue for gcc. Not
		// that gcc can use the SDK headers at all (I think clang fares much
		// better), so you have to use bootleg SDK w32api, which is incomplete
		// and I suspect full of undiscovered bugs. This is, I think, an
		// entirely political matter for the gcc project, because it's not like
		// their compiler doesn't already bend the C language into a pretzel to
		// support a wide variety of proprietary platform SDKs full of non-
		// standard features. In the end we got clang out of the mess, so I
		// can't complain
		LPOLESTR name = OLESTR("CreateTextFile");

		hr = IDispatch_GetIDsOfNames(
			fso,
			&IID_NULL,
			&name,
			1,
			lcid, // No idea who thought it was a good idea to make method name
			      // lookup locale-sensitive, but we'll play along
			&dispid);
	}

	// Meet BSTRs, one of OLEs core data types. They are pooled and counted
	// UTF-16 strings allocated with the task allocator. Not to be confused
	// with LPOLESTRs, which use the same character type but are plain old
	// unmanaged, NUL-terminated strings. Useless trivia: in the Mac OS port of
	// OLE (and I mean the old school Mac), BSTRs (and LPOLESTRs) use 8-bit
	// characters. I wonder about the UNIX port. If you didn't already know:
	// the Mac OS port was used to port Office, the UNIX port was used to port
	// Internet Explorer to Solaris and HP-UX. Said UNIX port both gave us a
	// usable browser on Solaris *and* the Windows 2000 source leak, so yay
	BSTR string = NULL;

	if (SUCCEEDED(hr))
	{
		if (string != NULL)
			SysFreeString(string);

		// Hey, we're three fourths through the second line of the script
		string = SysAllocString(OLESTR("c:\\testfile.txt"));

		if (string == NULL)
			hr = E_OUTOFMEMORY;
	}

	// IDispatch deals with VARIANTs, which are discriminated unions that can
	// contain all types supported by OLE. All arguments to methods are
	// passed as VARIANTs, and return values are returned as VARIANTs. This
	// variable is equivalent to the script variable of the same name, and
	// will receive the result of fso.CreateTextFile(...)
	VARIANT a;

	// VariantInit takes uninitialized memory and turns it into a VARIANT
	// that doesn't contain anything (type VT_EMPTY)
	VariantInit(&a);

	if (SUCCEEDED(hr))
	{
		VARIANTARG args[2];

		for (size_t i = 0; i < ARRAYSIZE(args); ++i)
			VariantInit(&args[i]);

		// In OLE, arguments are passed right-to-left, just to make things
		// more interesting

		// VARIANT_TRUE is not 1, it's -1! it's also a 16 bit value. Users
		// of old school Visual Basic will be familiar with this: Visual
		// Basic Integers are 16 bits, and True is -1 (because Visual Basic
		// uses bitwise operators for logic, so Not False is -1, and And and
		// Or are not short-circuiting)
		args[0].vt = VT_BOOL;
		args[0].boolVal = VARIANT_TRUE;

		args[1].vt = VT_BSTR;
		args[1].bstrVal = string;

		// BSTRs don't support shared ownership: the first argument to fso.
		// CreateTextFile(...) now owns the string, so we forget about it
		string = NULL;

		// This structure describes the argument to a method invocation:
		DISPPARAMS params;

		// ... the argument values, as an array of VARIANTs...
		params.rgvarg = args;
		// ... the dispids of named arguments, as an array of DISPIDs...
		params.rgdispidNamedArgs = NULL;
		// ... and the element counts of the above two arrays:
		params.cArgs = ARRAYSIZE(args);
		params.cNamedArgs = 0;

		// And finally, we invoke the method!
		hr = IDispatch_Invoke(
			fso,
			dispid,
			&IID_NULL,
			lcid, // Locale-sensitivity makes a little more sense here
			DISPATCH_METHOD, // The kind of invocation. Other invocation types
			                 // are property get, property put and property set
			                 // (put is for values, set is for objects -
			                 // respectively Let and Set assignments in Visual
			                 // Basic)
			&params,
			&a, // Easy to miss, but the return value is here
			NULL, // This is where we receive detailed error information, but
			      // gently caress it, this is complicated enough already
			NULL); // And this is where we receive the index of the invalid
			       // argument, in case the call can't be prepared because of
			       // an invalid argument (e.g. if it can't be typecast to the
			       // type specified by the metadata)

		// Free the argument list, we don't need it anymore
		for (size_t i = 0; i < ARRAYSIZE(args); ++i)
			(void)VariantClear(&args[i]);
	}

	if (SUCCEEDED(hr))
		// VARIANTs have a standard typecasting function, and we use it here
		// to cast the return value of fso.CreateTextFile(...) to an object,
		// i.e. an IDispatch *
		hr = VariantChangeType(&a, &a, 0, VT_DISPATCH);

	if (SUCCEEDED(hr))
	{
		// Third line of the script, yay!
		LPOLESTR name = OLESTR("WriteLine");

		hr = IDispatch_GetIDsOfNames(
			a.pdispVal,
			&IID_NULL,
			&name,
			1,
			lcid,
			&dispid);
	}

	if (SUCCEEDED(hr))
	{
		if (string != NULL)
			SysFreeString(string);

		string = SysAllocString(OLESTR("This is a test."));

		if (string == NULL)
			hr = E_OUTOFMEMORY;
	}

	if (SUCCEEDED(hr))
	{
		// Not much to say here, same as above. Repeat for every, single,
		// drat method call

		VARIANTARG args[1];

		for (size_t i = 0; i < ARRAYSIZE(args); ++i)
			VariantInit(&args[i]);

		// Oh right, an interesting thing. Some methods have optional
		// positional parameters. The way you say you didn't pass an optional
		// parameter is not to omit it (I think that would make the invocation
		// fail) or pass an empty value (VT_EMPTY), but to pass a "missing
		// argument" error (VT_ERROR with a value of DISP_E_PARAMNOTFOUND),
		// which you have to admit is pretty drat clever
		args[0].vt = VT_BSTR;
		args[0].bstrVal = string;
		string = NULL;

		DISPPARAMS params;

		params.rgvarg = args;
		params.rgdispidNamedArgs = NULL;
		params.cArgs = ARRAYSIZE(args);
		params.cNamedArgs = 0;

		hr = IDispatch_Invoke(
			a.pdispVal,
			dispid,
			&IID_NULL,
			lcid,
			DISPATCH_METHOD,
			&params,
			NULL,
			NULL,
			NULL);

		for (size_t i = 0; i < ARRAYSIZE(args); ++i)
			(void)VariantClear(&args[i]);
	}

	if (SUCCEEDED(hr))
	{
		// And finally, the last line of the script, Jesus wept
		LPOLESTR name = OLESTR("Close");

		hr = IDispatch_GetIDsOfNames(
			a.pdispVal,
			&IID_NULL,
			&name,
			1,
			lcid,
			&dispid);
	}

	if (SUCCEEDED(hr))
	{
		// Can't think of anything interesting to say here
		DISPPARAMS params;

		params.rgvarg = NULL;
		params.rgdispidNamedArgs = NULL;
		params.cArgs = 0;
		params.cNamedArgs = 0;

		hr = IDispatch_Invoke(
			a.pdispVal,
			dispid,
			&IID_NULL,
			lcid,
			DISPATCH_METHOD,
			&params,
			NULL,
			NULL,
			NULL);
	}

	// Clean up everything. Everything! Some of these could be cleaned up
	// earlier, but I'm not a compiler and I'm not going to do scope analysis.
	// Not that the Visual Basic compiler is much more sophisticated than this.
	// It is, in fact, pretty vile in pretty much all aspects of compilation
	if (string != NULL)
		SysFreeString(string);

	(void)VariantClear(&a);

	if (fso)
		IDispatch_Release(fso);

	// Some COM servers don't support CoUninitialize properly. You're supposed
	// to keep a per-server reference count, and as long as the reference count
	// is > 0, the server won't be unloaded (e.g. the DLL of an in-process
	// server won't be freed. The DLLs export a function called DllCanUnloadNow
	// which returns whether the DLL can be unloaded, i.e. whether its
	// reference count is 0). Some classes do things like spin threads without
	// bumping the reference count... not that you can do that in a truly
	// thread-safe way: you decrement the reference count and exit the thread,
	// but these are at the very least two distinct, non-atomic instructions,
	// with a tiny but not non-existent window for race conditions while the
	// reference count is 0 but the instruction to exit the thread hasn't been
	// executed yet. At least they could bump the DLL itself's reference count
	// as long as live threads could run code in it... except *that* couldn't
	// be done safely until Windows XP, which introduced GetModuleHandleEx and
	// FreeLibraryAndExitThread
	CoUninitialize();

	if (FAILED(hr))
		return EXIT_FAILURE;

	return EXIT_SUCCESS;
}

Bloody
Mar 3, 2013

i don't understand you

Space Whale
Nov 6, 2014

abraham linksys posted:

it's real good times. i keep referencing the "wat-like" behavior because i've definitely seen code samples where this can gently caress poo poo up badly, like the original wat talk might actually have this in there (i should just rewatch it). i want to say you can get an array into a state where length returns the incorrect value, or something equally strange?

I thought I had an array of arrays of arrays. I really had an array of arrays of object-things with some numeric properties from 0 to n.

.length was undefined on the innermost array-like-thing and that's where I found the for-in idiom. When debugging I just saw the inner for loop never triggered at all, and it was because of two name properties just thrown onto the inner array because the prior dev was an rear end in a top hat. Adding these non numeric properties basically hoisted it (on it's own petard!) into object-dom so array stuff quit working.

So, "just iterate over its properties!"

:psypop:

jony neuemonic
Nov 13, 2009

hackbunny are... are you okay?

Adbot
ADBOT LOVES YOU

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av

jony neuemonic posted:

hackbunny are... are you okay?

I wonder sometimes. I actually liked doing it

  • Locked thread