w3c / FileAPI

File API
https://w3c.github.io/FileAPI/
Other
104 stars 44 forks source link

Readonly attributes without setters? #126

Closed andrew-aladev closed 5 years ago

andrew-aladev commented 5 years ago

You made all attributes readonly for File API. But you don't want to provide any setters. People have to recreate File object just to change one attribute and loose performance.

Where is setName, setLastModified, setType, setSize, etc?

Do authors of this spec have any functional fetish? It makes your API unusable for people without that fetish. Maybe some authors forget that they are making API for whole Earth. I am here to remind it.

Is there any real reason to keep File API without setters? Any other JS APIs have all possible setters available.

andrew-aladev commented 5 years ago
setName (file) {
  return new File(
    [file.slice(0, file.size)],
    'file',
    { type: file.type }
   )
}

Do you mean that it looks like API? I don't think so. It looks like people on this planet have to dance around madness.

annevk commented 5 years ago

@andrew-aladev please familiarize yourself with https://www.w3.org/Consortium/cepc/.

andrew-aladev commented 5 years ago

@andrew-aladev please familiarize yourself with https://www.w3.org/Consortium/cepc/.

You already done File API that makes pain for everyone human on this planet. Don't you think that it is too late to point at any rules? People wants to change file name. They see stackoverflow solutions like:

file.__proto__.setName = (name) => (
  new File(
    [this.slice(0, this.size)],
    name,
    { type: this.type }
   )
)

Respect is the genuine consideration you have for someone (if only because of their status as participant in W3C, like yourself), and that you show by treating them in a polite and kind way.

Where is your respect? I see that you have no respect for people that are using your "API".

Maybe you need to change your rules. First respect should be provided from w3c developers to users. Only after that w3c can ask users for respect.

andrew-aladev commented 5 years ago

@annevk, I am reading this readonly properties without setters as "w3c developers want functional programming, they don't want to maintain any state inside these objects". So regular user have to wrap file/blob with object that maintains all required properties and implement toNative method that does conversion to native file/blob.

I don't want to offend anyone, but I won't provide any respect. I want just to know whether I am wrong to proceed doing my job.

annevk commented 5 years ago

The API might not offer what you want from it, but it can be a useful property that when you hand someone an object, they cannot change it from underneath you. And conversely, as you noted, there are use cases better suited with more mutability. As with all engineering, this is a trade-off. And discussing such a trade-off is best done in a professional manner.

andrew-aladev commented 5 years ago

The API might not offer what you want from it.

I think that File is an object that have name, last modified, blob, etc. Rename operation on file should changes its name. Where is this method?

If your File do not offer this functionality why it's name is not __FileInternal?

it can be a useful property that when you hand someone an object, they cannot change it from underneath you

It is functional programming method for protecting objects like __FileInternal, it is not suitable for File. You can't even imagine what amount of wrapper people have implemented around this API. Every new project comes with its own file/blob wrapper that does the same job - maintains properties inside.

And conversely, as you noted, there are use cases better suited with more mutability.

So where is mutable wrapper around __FileInternal? What amount of years people have to wait before it will be available in all browsers? But nobody will actually replace existing wrappers in existing projects. Nobody will pay money for that job. These wrappers are a great monument for anyone who love functional programming so much, that any mutable API was just not implemented.

As with all engineering, this is a trade-off

No need to any trade off here, just do not ignore mutable API. Please do not forget that you are working on API that people around planet will use.

annevk commented 5 years ago

Well, per https://extensiblewebmanifesto.org/ exposing low-level primitives and letting others build on those is well within our scope. It would be useful to have pointers to libraries that wrap Blob-like objects in the manner you describe and see their adoption figures, as well as the Stack Overflow questions you allude to. That might help clarify what needs to be done here. https://whatwg.org/faq#adding-new-features might also be helpful reading.

andrew-aladev commented 5 years ago

@annevk, We have already a good example what I want: Date. Its API is mutable. Libraries like Date fns are built around them to provide immutable API for everyone who wants:

useful property that when you hand someone an object, they cannot change it from underneath you

So mutable comes first, immutability wrapper is around it. All people are satisfied. Is it clear?

mkruisselbrink commented 5 years ago

So mutable comes first, immutability wrapper is around it. All people are satisfied. Is it clear?

You can't wrap a mutable object in a way to make it immutable. If the "immutable" wrapper really just wraps the underlying mutable object, it is still possible for that underlying mutable object to be mutated. As you demonstrated, the other way around there are no such limitations. You can perfectly wrap a immutable object into a mutable one. Also because of the immutability of blobs and files, creating new ones from other ones is a fairly inexpensive operation (although I would skip the slice, just pass the existing blob/file directly to the constructor of the new one).

So I don't see us making any changes here. Blobs and Files are conceptually immutable objects. If you want mutability you can create your own wrappers on top. As anne said, if you can point to widely used libraries that add such a wrapper that might make us reevaluate the use for one, but for now I don't see any reason to add that to this spec.

guest271314 commented 5 years ago

@annevk cc @andrew-aladev

@andrew-aladev please familiarize yourself with https://www.w3.org/Consortium/cepc/.

Respect is the genuine consideration you have for someone (if only because of their status as participant in W3C, like yourself), and that you show by treating them in a polite and kind way.

2 cent (TL;DR): The term "respect" is frequently used on boards as some form of would-be "immutable" and objective standard though is not objective whatsoever.

"respect" is an emotion; a feeling. Human feelings can and do change between one moment to the next. If an individual relies on the feeling that they are being "respected" by another individual they can easily be lead to their own demise if they believe that the other individual has a "genuine consideration" for them. Only when the one-way door closes behind them will they learn that the individual only appeared to "respect" them. "respect" is a feeling that necessitates reliance on another individuals' state of mind and motivations, which they do not have to convey to you at all, though outwardly could be taken as "genuine consideration". If an individual entertains the concept of "respect" they MUST determine and supply that "respect" to and for themselves OR be beholden to another individuals' emotional state. Otherwise, "respect" is irrelevant. When individuals refer to another not "respecting" them they are actually describing their own internal emotional state, their sensitivities; which again, is subject to change at any time, and is their own feeling. Individuals on boards can cite "rules" for "respect", though they could be hypocrites (https://twitter.com/guest271314/status/1102262058744082433), and use the non-observable term "respect" to stifle questions and answers that they do not like, while simultaneously promoting their own beliefs (https://meta.stackoverflow.com/a/342940/), "respectfully". Once an individual starts travelling along the rabbit proof fence of "respectful" and "disrespectful" words they can find any number of words and terms that could be considered "offensive" or "disrespectful" - if they entertain such notions, and can be "offended" by mere words. Similarly, an individual could arbitrarily label any number of words and terms "offensive" in order to limit the context of the subject matter and topics, by labeling words "disrespectful" or "offensive", which are simply emotions. A couple examples of the issues with "respect" and what some individuals' label as "offensive" or "discriminating" against others' beliefs (essentially taking the position that an individual MUST belief what another individual believes, without question)

Question: Is quoting Lou Reed's use of “colored” offensive or unwelcoming? https://english.meta.stackexchange.com/questions/12046/is-quoting-lou-reeds-use-of-colored-offensive-or-unwelcoming/12051

Answer (deleted by admin.): https://plnkr.co/edit/5CwKsW?p=preview

Question: What does Farrakhan mean by “false Jews”? https://politics.stackexchange.com/questions/35178/what-does-farrakhan-mean-by-false-jews

Answer (deleted by mod): https://gist.github.com/guest271314/ba0a80bc96b57a36fb6f40e116b4cb8a

The first Q/A illustrates the issue with trying to create a pseudo standard for determining if certain words are "offensive". Objectively, if "colored" is "offensive" then "White", "Black" and "Jew", et al. must also be "offensive", as they are merely political classifications. "Black" could be considered even more "offensive" than "colored", as the term "Black" as defined by the U.S. Census Bureau attempts to arbitrarily create more than one "Black" "race" and the definition of "White" portends to create a fictional location termed "North Africa", which cannot be found on any map. Point out those discrepancies and an individual could be called being "disrespectful" or "offensive".

The second Q/A illustrates that some individuals' questions might at first glance be impartial, though once an objective answer is provided the actual intent of trying to illicit one or more answers tailored to support their predisposed beliefs could be revealed.

"respect" could have different meanings in different contexts. In a match or competition "respect" could translate into meaning legitimate fear of the opposing teams' capabilities, that is, out of fear for what could occur to them if they perform they action which gives their opponents an advantage - not being "polite" or "kind" out of consideration for them.

No individual can make another individual feel any particular way, or objectively declare what "respect" is. An individuals' feelings are not observable, only their actions are observable. Emotions and feelings have nothing to do with asking technical, historical, or any other questions, in any field of endeavor. Consider the above well whenever an individual or institution uses the term "respect": they could very well be trying to invoke an emotional state or reaction to distract from the actual practical and/or technical issue or facts of the subject matter.

Goebbels was in favor of free speech for views he liked. So was Stalin. If you’re really in favor of free speech, then you’re in favor of freedom of speech for precisely the views you despise. Otherwise, you’re not in favor of free speech. Noam Chomsky.

--

Relevant to setters for File, it is not clear what such functionality would mean. File/Blob are stored in memory. With adequate effort (reading the source code of FOSS browsers) an individual could locate where the Blob is stored in memory and change the contents of the file, see

and consider the "special" case of URL.createObjectURL() for MediaSource(), which is not consistent with the specification, see https://github.com/w3c/media-source/issues/209

1.2 Definitions

MediaSource object URL

A MediaSource object URL is a unique Blob URI [FILE-API] created by createObjectURL(). It is used to attach a MediaSource object to an HTMLMediaElement.

These URLs are the same as a Blob URI [FILE-API], except that anything in the definition of that feature that refers to File and Blob objects is hereby extended to also apply to MediaSource objects.

(see also ; https://github.com/w3c/media-source/issues/211)

Thus, an individual could ask if Blobs are "immutable"? And further, if the MediaSource() specification is true and correct, can users get the underlying data pointed to by a Blob URL which was created by passing a MediaSource instance? The short answer is no, which can be quickly confirmed. Therefore, there are inconsistencies relevant to different specifications and Blob (File), Blob URLs; there are also different implementation at Chromium and Firefox for reading/processing uploaded directories, see How to upload and list directories at firefox and chrome/chromium using change and drop events https://stackoverflow.com/q/39664662. Perhaps the proposed https://github.com/WICG/native-file-system will lead to a uniform implementation of reading/writing files and directories.

The Filesystem API (still implemented/shipped at Chromium/Chrome) currently provides a means to read/write to the "same" File object. Or, Native Messaging could be used to directly change attributes of a file. Though that would necessarily change the file, correct?

What are you trying to achieve by setting a different name or lastModified property of an existing File object? What is the requirement?

andrew-aladev commented 5 years ago

@mkruisselbrink, Hello. If you love functional programming so much I can't do anything. I will just wait until functional bubble will decrease. It is possible to wrap any mutable into immutable and vice versa, it doesn't matter.

What can you say about naming of blob/file classes? Do you think it is fine to name File that have no any file like methods as File? I don't think so. Will you try to find another names for these classes? Thank you.

mkruisselbrink commented 5 years ago

If we'd redesign this API from scratch, yeah, we'd possibly name things differently. At this point there really ins't much we can do about that. There is way too much usage out there of the existing names, so renaming isn't an option. We could add an alias or something with a different name, but that would just cause even more confusion, as now there are two names for the same thing. It is unfortunate that "historical" APIs name squat names that arguably could be used better for other concepts, but there isn't much we can do about that at this point.

andrew-aladev commented 5 years ago

"respect" is an emotion; a feeling.

So many words, sorry. My feeling is simple. You can't rename file without madness. It means that File is not actually a file, maybe it is some kind of internal stuff, that users shouldn't touch. It means that developers that created interface doesn't care about users. Users shouldn't give any additional respect to these people, it is obvious.

If we'd redesign this API from scratch, yeah, we'd possibly name things differently. At this point there really ins't much we can do about that. There is way too much usage out there of the existing names, so renaming isn't an option. We could add an alias or something with a different name, but that would just cause even more confusion, as now there are two names for the same thing. It is unfortunate that "historical" APIs name squat names that arguably could be used better for other concepts, but there isn't much we can do about that at this point.

Ok, I see. It will become a new legacy API. So please try to select proper terminology for future APIs, it is important. Please do more discussion with different people. If you love functional programming, please find non-functional humans and discuss terminology with them too. Thank you.

guest271314 commented 5 years ago

@andrew-aladev

You can't rename file without madness.

What do you mean? You can create a new File object. When a file is "renamed" the file is changed anyway, correct?

What is the specific use case?

andrew-aladev commented 5 years ago

What do you mean? You can create a new File object. When a file is "renamed" the file is changed anyway, correct?

See, you said "File object" automatically instead of "File instance" because it is not an instance. It is some kind of FileData/FileBlob etc.

I want new File(...).setName('file'). I saw this code as new FileWrapper().setName('file').toNativeFile() in many closed source projects, that I can't show. Today I saw it again. Each project has its own bicycle wrapper with its own terminology and complexity. Developers of this "File" interface should know about this situation. Why not?

guest271314 commented 5 years ago

@andrew-aladev Why is the name of the File object or instance important?

What does .toNativeFile() do? Is the context JavaScript?

If the requirement is to create a "file" that can be changed you can utilize data URL (data URI) data:[<mediatype>][;base64],<data>

let file = "data:text/plain,abc" // mediatype and data "abc" can be changed at any time by the developer, unless the variable is declared with const

If you are offering the file for download you can suggest a file name using the download attribute at an HTML <a> element, though the user can change the name of the file at any time. Verifying that a download took place at all is a different matter Detect when user accepts to download a file https://stackoverflow.com/q/41334881, though is possible, to an appreciable degree, where user action consistent with the procedure https://stackoverflow.com/a/41336449. Otherwise am not certain what changing the name or lastModified properties of a File instance achieves, at least without a context as to why such a procedure is important.

Still not gathering the use case?

guest271314 commented 5 years ago

@andrew-aladev

It is some kind of FileData/FileBlob etc.

Perhaps take the time to read the links at the previous comments as to how Blob/File are stored within "memory", e.g., the browser configuration directory, see https://stackoverflow.com/questions/38239361/where-is-blob-binary-data-stored#comment63940603_38239361.

Today I saw it again.

Where? What was the context and purpose of changing the file name or lastModified properties of a File "instance"?

guest271314 commented 5 years ago

@andrew-aladev Note, technically, it is possible to set the name property of the File instance utilizing FormData(), append() and/or set() methods

var fd = new FormData();
var file = new File([1], "originalFileName.txt", {type:"text/plain"});
fd.append("fileName.txt", file);
console.log([...fd][0][1].name);
fd.set("fileName.txt", file, "newFileName.txt");
console.log([...fd][0][1].name);

plnkr https://plnkr.co/edit/xLqWR1?p=preview

guest271314 commented 5 years ago

@andrew-aladev At the code at the previous comment/plnkr if you check the lastModified property you will observe that the instance set at FormData has the same value as the original file variable

setTimeout(() => console.log(fd.get("fileName.txt"), file), 3500)

andrew-aladev commented 5 years ago

Why is the name of the File object or instance important?

Perfect terminology says almost everything about underlying code. It is just an another way to differ good code from bad by using fast photographic perception. It may be important for many developers.

What does .toNativeFile() do? Is the context JavaScript?

It executes File constructor with wrapped params when you actually need native file data object.

If the requirement is to create a "file" that can be changed you can utilize data URL (data URI) data:[][;base64],

It is not so complex. People wants to create a file, fix its name, extension, check mime type, manipulate its blob a bit using their own infrastructure with mutable instances or with other immutable objects. Nobody is using File class in the way it was designed. People uses their own classes and creates File only when they need its methods (or inherited methods). Noone wants to extend File. It is a complete interface failure.

Note, technically, it is possible to mimic setting the actual name property of the File instance utilizing FormData(), append() and/or set() methods

var fd = new FormData();
var file = new File([1], "originalFileName.txt", {type:"text/plain"});
fd.append("fileName.txt", file);
console.log(file === [...fd][0][1]); // true
fd.set("fileName.txt", file, "newFileName.txt");
console.log(file === [...fd][0][1]); // false

It looks like FormData is the only class on this planet that uses File in the way it was designed. It recreates File on every sneeze. People will just change internal wrapper params and creates File only when they need it.

guest271314 commented 5 years ago

@andrew-aladev

It is not so complex. People wants to create a file, fix its name, extension, check mime type, manipulate its blob a bit using their own infrastructure with mutable instances or with other immutable objects.

That is already possible.

Nobody is using File class in the way it was designed.

That is not accurate. Who is "Nobody"? How did you determine that?

Noone wants to extend File

To do what?

It is a complete interface failure.

Disagree.

People will just change internal wrapper params and creates File only when they need it.

That is already possible. Users can create a FormData object as a "template" and use fetch() or XMLHttpRequest() to read/write the contents of one or more files (see Get HTTP Body of Form in JavaScript https://stackoverflow.com/q/40111982)

var form = document.querySelector("form");
form.onsubmit = (e) => {
  e.preventDefault();
  var formData = new FormData();
  var input = e.target.querySelector("input");
  formData.append("file", input.files[0], input.files[0].name);

  var response = new Response(formData);
  var stream = response.body;
  var reader = stream.getReader();
  var decoder = new TextDecoder();
  reader.read()
    .then(function processData(result) {
      if (result.done) {
        console.log("stream done");
        return;
      }
      var data = decoder.decode(result.value);
      console.log(data);

      return reader.read().then(processData);
    })
    .catch(function(err) {
      console.log("catch stream cancellation:", err);
    });

  reader.closed.then(function() {
    console.log("stream closed");
  });
}

and/or write a form data including one or more "files" (that can be modified at any time) from scratch (see https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html; https://github.com/whatwg/fetch/issues/392; https://github.com/whatwg/html/issues/3040; How to manually create multipart/form-data https://stackoverflow.com/q/47080869).

It looks like FormData is the only class on this planet that uses File in the way it was designed.

Not sure what you mean? FormData is not the only API shipped with the browser that can create a "file". It is only relatively recently that users could even create a File object (or instance). In which specific manner to you want to "extend" File? Again, are the use cases?