Force Document to Front

First off, I just want to say that Document is an excellent class, & thank you.

Unfortunately… some of it’s functionality appears to be unstable on Windows, (citing the comment made regarding ‘Text-Mirroring’ from Document.sc) and I need a way to make force this to work…

// the following does not *always* work 
// when called from an outside function...

// specifically, the document may flicker *to*
// and then *back* to, the calling document 
((
	this.x_ 
	(
		writeArchive 
		
		(
			global( Archive ).asCompileString // readable version
			,
			pathname:( Archive.archiveDir +/+ "front.txt" ) // x, write path 
		)
	)
	; // need this to work:
	
	front // force  
	
	(
		Document open: x // must use Document
	)
))

Are there any internal methods for class Document that I may not be utilizing?

Or a way to construct a sync function?

Thanks in advance,

- Rain

I don’t have anything helpful to add - but I’m curious where the syntax

Document open: x

comes from. I’ve never seen sclang written like that

yep you can format messages as operators so

min(3,5)
3 min: 5
3.min(5)

are all equivalent

It’s a style choice… always good to know every option:

x = Archive.archiveDir +/+ "archive.sctxar"

Document.open (x)
open (Document, x)
Document open: x
\open.applyTo (Document, x)
Document.perform (\open, x)
applyTo (\open, Document, x)
perform (Document, \open, x)

// .openDocument is a shortcut for Document.open

// implemented as a String instance method

x.openDocument

openDocument (x)

Message(x, \openDocument).( )

MethodQuote(\openDocument).(x)
4 Likes

I’m afraid I don’t see a sync mechanism in Document.

Nor do I see why the IDE would flicker between documents. Tracing through the code for Document.open:

  • If the path was already open, simply .front it.
  • Otherwise, initFromPath:
    • Get an ID.
    • Initialize the sclang text mirror.
    • Tell the IDE to open the file.
    • Set instance variables.
    • Add the document to the collection.

None of the initFromPath steps explicitly fronts any document – so I suppose it’s assumed that the IDE will bring any newly-opened document to the front.

Also missing from that execution flow is an instruction to bring any other document to the front.

It would have to be some kind of race condition, but I don’t see where it could happen.

You might have to run that in a routine and insert a short wait before front?

That’s an interesting question… it’s something I had wanted to bring up for a while, but I couldn’t find a way to do it that was not over-prescriptive.

For an analogy, let’s say that I Google “dogs working” instead of “working dogs.” I could call that a style choice. And the former query does return results about working dogs – so I could say that either wording communicates the intent of the query to the search engine, so both are legitimate.

But to a human reader, “dogs working” connotes activity that happens to be carried out by dogs, while “working dogs” connotes a category of animals. If the context is the category of animals, then the former wording communicates less accurately, or more awkwardly, to human beings.

SC accepts the code style in the initial post – but I think it might not communicate optimally with human beings. I think both are important in programming.

Concretely, for instance, front(Document open: x): the best that I could say about it is that it perhaps emphasizes the final result – “1. something should be brought to the front; 2. that ‘something’ is…” – while the more typical formulation Document.open(x).front emphasizes first who should perform the action – “Hey you! Document!” – and then a sequence of operations in the order of evaluation (“first open, then take that thing and ‘front’ it”).

I’m trying hard here not to argue simply what I’m accustomed to – but, I think there are concrete benefits to putting the receiver first, and to writing operations in evaluation order as much as possible. If there is a benefit to inverting the order, I’ll be honest that I don’t see it.

A possible drawback is, if you have a question about an especially complex block of code and the style is harder to understand, this might deter people from helping you. I don’t know about others, but I’m often quite busy. If it’s a difference between 5 or 15 minutes to understand a block of code, because of style choices, I might simply skip that question even if it’s interesting.

I know of one non-equivalence, because of a compiler optimization:

(
r = Routine {
	(1 .. ).do { |i|
		i.yield;
	}
};
)

r.next;  // 1, 2, 3, 4

(
r = Routine {
	(1 .. ) do: { |i|
		i.yield;
	}
};
)

r.next;
ERROR: Primitive '_SimpleNumberSeries' failed.
Wrong type.

… because the first (1..).do compiles to forSeries, while the second compiles such that it would first try to construct an infinite series as an array – of course an infinite-size array can’t exist, so SC sensibly fails the attempt. (do((1 .. )) { |i| i.yield } is also OK.) Apparently a keyword: binary op must always operate on an object, and can’t fold series expressions into other methods.

One could say that’s a compiler bug (it surprised me when I found it mentioned in SC help), but it at least suggests that you can’t always assume the three method call syntaxes are equivalent.

hjh

1 Like

James… I never stated that putting front “in front” of the call to open the Document, was a style choice.

This can clearly be seen, in the original response to @droptableuser.

And I completely understand, that you must be so accustomed to being the ultimate force of guidance to this community, which I truly & sincerely thank you for, wholeheartedly; however, I believe it may cause you to go through things perhaps just a little too fast, on occasion.

I still marked your post as the :white_check_mark: Solution because you said to put it all in a Routine, and I still liked it because you took the time to go through the source for me, which I truly & sincerely thank you for.

Fair enough – anything prescriptive that I said could be taken with a grain of salt, or completely ignored. You can, of course, write however you like.

At the same time, if I see:

x = Archive.global.asCompileString
.writeArchive(Archive.archiveDir +/+ "front.txt");

Document.open(x).front;

… I understand it immediately (and can see right away that it actually won’t work as expected, because writeArchive doesn’t return the pathname to assign to x – “ERROR: Document open failed”).

But if I see the code example at the top of the thread, it takes more effort to decipher, and I might simply not have time or mental energy to look at it carefully. (In fact, when I wrote my first reply, I completely missed that x was being assigned a wrong value – when I rewrote it, the x thing was obvious to me – so the code style negatively impacted the quality of my reply. If you’re OK with that, then there’s no problem :handshake: )

I do think the code style is a worthy experiment – just pointing out potential difficulties with it.

hjh

:dizzy_face:

I specifically remember testing this code, and having x assigned the value of the path, and not the object being written to it.

Perhaps I must have been the one, working too fast…

To each his own, I suppose, though I do see a critical aspect in your point of view, and it’s never without my own critical consideration.

:v:

I think it is important to know the variations that are possible, especially as not all of them are purely stylistic choices:

Control structures in SuperCollider examples don’t typically follow the receiver - message flow. And using and or or within an if statement, the recommended syntax is if(valUnderTest and: { ... }) for optimization reasons, right?

It might make for a good help file in the Language reference section to point of the various ways of doing the same thing as Rainer did in their post.

Anyway, I appreciate reading these threads to pick up bits like this! Thanks everyone for the discussion.

1 Like