Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#cd compiler directive is ignored when #load-ing the script #1392

Closed
matthid opened this issue Jul 30, 2016 · 14 comments
Closed

#cd compiler directive is ignored when #load-ing the script #1392

matthid opened this issue Jul 30, 2016 · 14 comments

Comments

@matthid
Copy link
Contributor

matthid commented Jul 30, 2016

When using #load preprocessor directives like #cd are ignored.

Repro steps

test.fsx

#cd "g"
#cd __SOURCE_FILE__
#load "other.fsx"
#cd __SOURCE_DIRECTORY__

g/test.fsx/other.fsx

printfn "other.fsx"
  1. fsi
  2. #load "test.fsx"

Expected behavior

other.fsx

Actual behavior

test.fsx(3,1): error FS0079: Could not load file 'C:\PROJ\visualfsharp.issues\loadWithCd\other.fsx' because it does not exist or is inaccessible

Known workarounds

Currently none.

Related information

Executing the file directly

fsi test.fsx

yields the expected output:

other.fsx

I used this originally because I cannot write something like

#load ("g/" + __SOURCE_FILE__ + "/other.fsx")
@dsyme
Copy link
Contributor

dsyme commented Aug 2, 2016

@matthid As things stand, this is by design - like some of the other directives, #cd isn't for use in #loaded scripts. But this should be made clear somewhere, and a warning given

Supporting it in some form might make sense, though really we should just support something like what you mention:

#load ("g/" + __SOURCE_DIRECTORY__ + "/other.fsx")

@matthid
Copy link
Contributor Author

matthid commented Aug 3, 2016

@dsyme I assumed something like that, but what do you think of the inconsistency with FCS? IE it uses '#load' for it's EvalScript functionality, this is surprising at the very least.

As well as scripts behave differently between executing in fsi and '#load' ing them. This is really unexpected and shouldn't exist (see all the related other bugs/quirks).

Is it possible to just make '#load' do the same as fsi and get rid of all the quirks (including this) even if it means to make things possible which are not specified/documented?

@matthid
Copy link
Contributor Author

matthid commented Aug 3, 2016

One more note about the other syntax: Currently its really simple for tools like Fake to calculate a hash. We just follow all '#load' links and calculate a hash for all contents. This might be (maybe?) more difficult to do with the '+'. At least it breaks constructs like that (I think we can easily fix it in fake, this is just to show that others might depend on this somehow).

@dsyme
Copy link
Contributor

dsyme commented Aug 3, 2016

@matthid I think you should use FCS's EvalInteraction instead of EvalScript to get consistency? We'll aim to take a look at the other inconsistencies one by one (they aren't easy to fix though...)

@matthid
Copy link
Contributor Author

matthid commented Aug 3, 2016

I think FCS should do that in EvalScript...

Not exactly easy is perfect to start. I would try to take a look. Good would be a general guide at how you ideally would like to solve that. So you agree that #load "script.fsx" should behave like fsi script.fsx? I think that would be an improvement in F# scripting capabilities, as you expect that you can just move code to a different file, #load it and it still works.

@dsyme
Copy link
Contributor

dsyme commented Aug 5, 2016

In the F# scripting model there is a distinction between

  1. referencing a compiled DLL (via #r or -r).
  2. referencing source code as a "compiled, referenced and initialized" component (via a #load or --load:script.fsx).
  3. using a script as an interaction (via console input, or --use:script.fsx or just script.fsx on the command line)

For (1), the DLL is referenced but the initialization code is not forced eagerly.

For (2), the documentation for #load says

#load "file.fs" ...;;  Load the given file(s) as if compiled and referenced

For these components:

  • If they are scripts, #r, #I, #nowarn and transitive #load directives are taken into account.
  • All other directives like #cd, #help and #q are ignored - they are considered to be part of the language of "interactions" (see 3 below).
  • The contents of the "compiled and referenced" script are placed in an implicit module based on the filename of the script.
  • The initializers of the #load'd code are forced eagerly ("compiled and reference" should really say "compiled, referenced and initialized" for complete clarity)
  • If the same component is referenced twice via a "diamond" dependency, then it is only loaded once, i.e. a compilation and initialization order is implied by a depth-first traversal of the #load graph.

For (3) , "interaction"s:

  • the script is used as if entered as console input
  • #cd, #help, #q are respected
  • The code is checked-then-run in multiple fragments delimited by ;;.
  • No implicit module is used.
  • The initializers of the interaction (and any #load'd components implied by the interaction) are forced eagerly.
  • Each interaction will cause the #load of zero or more category (2) components.

@matthid
Copy link
Contributor Author

matthid commented Aug 5, 2016

@dsyme First thank you for the detailed answer!

Second: I'm really sorry for my ignorance here. I (kind of) understand the current split. What I'm generally asking here if it makes any sense (from a non-technical view). IE are there any reasons to do this besides technical ones?

This design really leads to a lot of situations considered as bugs by most people (when it is in fact "working as designed").

Also I don't understand how that fits with this simple sample:

test.fsx

#load "testecho.fsx"

testRef.fsx

#r "testecho.dll"

testecho.fsx

printfn "Test"

fsi test.fsx
echos Test, isn't this an interaction from testecho.fsx?

fsc -a testecho.fsx && fsi testRef.fsx
echos nothing

So you consider this as bug?

Maybe there should be another way of loading scripts interactively? Wouldn't that be even more confusing for users?

This may look like we are drifting away from this issue, but ultimately I would like to provide my help in implementing support for this scenario one way or another. IMHO Saying this is by design is not sufficient from an FSharp.Compiler.Service point of view as this means we cannot do some interactions (prepare the Environment) and then load a script later (well we could load it line by line and enter it, but that shouldn't be the recommended way of doing this IMHO as #load seems like the natural choice and actually "works" in most situations)...

From a philosophical view: IMHO When you load a fsx file you expect it to contain all those additional interaction directives, so using #load should "just work".

@smoothdeveloper
Copy link
Contributor

@matthid just for the specific case of compiling testref.fsx and #r, I'd assume you'd need to open the module / invoke somehow the module initializer for something to be printed, could you check in the assembly where is this printfn call occuring?

@matthid
Copy link
Contributor Author

matthid commented Aug 5, 2016

@smoothdeveloper Yeah I know. I just wanna hear @dsyme's opinion on the discrepancy.

@dsyme
Copy link
Contributor

dsyme commented Aug 6, 2016

@matthid Initialization code for #load'd files are executed eagerly as part of the overall interaction which implies the #load.

I've updated my comment above to include #r referenced DLLs. For these, initialization code is always executed on-demand.

@dsyme
Copy link
Contributor

dsyme commented Aug 6, 2016

@matthid I'm still not sure why EvalInteraction is not what you you want - it loads a category (3) interaction according to the description above. EvalScript loads a category (2) component. Perhaps you could add an FSharp.Compiler.Service issue with a failing test case using EvalInteraction?

@matthid
Copy link
Contributor Author

matthid commented Aug 6, 2016

@dsyme Do you mean reading the script completely and using EvalInteraction?
Yeah that would probably work, will try it.

I still think this is the root cause for a lot of confusion, which is really not needed. I mean at least we should print a warning if interaction directives are ignored (and a link to this thread). Even better would of course be if it worked "as a user would expect".

@matthid
Copy link
Contributor Author

matthid commented Aug 6, 2016

For anyone curious: See fsharp/fsharp-compiler-docs#621

You additionally should use the #line directive in order to get proper error messages. See https://msdn.microsoft.com/en-us/visualfsharpdocs/conceptual/compiler-directives-%5Bfsharp%5D#line-directives

@dsyme
Copy link
Contributor

dsyme commented Aug 8, 2016

I mean at least we should print a warning if interaction directives are ignored (and a link to this thread).

I agree

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants